Best Practices for HEAD requests

763 views
Skip to first unread message

Roger Hunwicks

unread,
Aug 12, 2015, 3:58:37 PM8/12/15
to Django REST framework
I am using DRF 3.1 to serve XML and HTTP requests to the "Get External Data" function in Microsoft Excel. Excel makes multiple HEAD requests prior to the GET used to fetch the data.

My understanding of the RFC and of DRF is that the RFC says that HEAD should return headers but no body, and that DRF iewsets accept HEAD requests by default but actually return the full GET, or at least generate the full GET.

These requests are large and take a long time to render (a couple of minutes) so I want to avoid waiting while Excel gets the data two or three times.

Is there a best practice recommendation on how to deal with HEAD requests in generic ViewSets?

It occurred to me that one possibility would be to recognize the HEAD request in in get_queryset and automatically return an empty queryset for that model.

Roger

Roger Hunwicks

unread,
Aug 12, 2015, 10:49:31 PM8/12/15
to Django REST framework
Further investigation shows that the HEAD request is correctly returning an empty response:

telnet localhost 8000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
HEAD
/api/mymodel/?format=xml&category=Category1&end_date=2015-04-30 HTTP/1.1
Host: myhost.mydomain.com
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)


HTTP
/1.0 200 OK
Date: Thu, 13 Aug 2015 02:39:12 GMT
Server: WSGIServer/0.1 Python/2.7.9
x
-xss-protection: 1; mode=block
x
-content-type-options: nosniff
Content-Language: en-us
Vary: Accept, Cookie
Allow: GET, POST, HEAD, OPTIONS
Cache-Control: no-cache
X
-Frame-Options: DENY
Content-Type: application/xml
Content-Length: 0


Connection closed by foreign host.


However, the server is still creating and then enumerating the queryset, which for an unpaginated response can take a long time.

As I expected, I can short-circuit the queryset enumeration by overriding get_queryset:

    def get_queryset(self):
        queryset
= super(MyModelViewSet, self).get_queryset()
       
# Head requests don't contain a body anyway, so there is no need to
       
# return the actual records
       
if self.request.method == 'HEAD':
           
return queryset.none()

Is there any downside to this? Should I be preparing a PR to add it to DRF itself?

Roger

Tom Christie

unread,
Aug 13, 2015, 11:30:53 AM8/13/15
to Django REST framework
> Should I be preparing a PR to add it to DRF itself?

Not really - it's probably fair enough to override this in cases like yours where there's an endpoint that's known to be critically slow,
but the safest thing to do in the general case is just to mock the entire response, and then not include the body.

It looks like a reasonable thing to do in your case tho - not aware that they'll be any downside. Best way to validate to yourself would be to do so and compare the response headers before and after. It's possible that the reported Content-Length will be erronous after your tweak (I assume that even for HEAD requests those are intended to be the *expected* Content-Length of an equivelent GET request, but haven't double-checked.

Roger Hunwicks

unread,
Aug 15, 2015, 2:46:44 PM8/15/15
to django-res...@googlegroups.com
From http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html "The Content-Length entity-header field indicates the size of the entity-body, in decimal number of OCTETs, sent to the recipient or, in the case of the HEAD method, the size of the entity-body that would have been sent had the request been a GET. Applications SHOULD use this field to indicate the transfer-length of the message-body".

I.e. yes, you're correct it should report the content-length of the equivalent GET, but fortunately it doesn't say MUST, so I think I'm ok to ignore it in my case.

--
You received this message because you are subscribed to a topic in the Google Groups "Django REST framework" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/django-rest-framework/jWhuoss6sfg/unsubscribe.
To unsubscribe from this group and all its topics, send an email to django-rest-fram...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages