Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
308 views
in Technique[技术] by (71.8m points)

python - How to create Route and View for HEAD http verb in Django Rest Framework

I would like to allow clients to send HTTP HEAD requests to my endpoint to allow them to check whether the resource exists without requiring the bandwidth to respond with the resource in the response body if it does. It should of course behave the same as GET but without sending the body of the response, just the header. I initially thought this would be handled by the DRF Router and ModelViewSet, but this question indicates that that isn't the case. Therefore I followed the advice in the answer posted there and wrote the following in urls.py and views.py:

project/urls.py

urlpatterns = [
        path('api/resource/<str:value>', views.ResourceViewSet.as_view(actions={'head': 'retrieve', 'get': 'retrieve'})),

app/views.py

class ResourceViewSet(viewsets.ModelViewSet):
    serializer_class = serializers.ResourceSerializer
    queryset = Resource.objects.all()
    lookup_field = 'value'

This setup isn't working for head requests. The get requests are all working as expected. Interestingly, the location and type of error I get depends on the client:

From Postman client I get Parse Error: The server returned a malformed response in the Postman console. The DRF logs however show it giving the correct response code and there are no errors on the server.

From CURL I get the correct response in the client, but the server throws a reset error:

ConnectionResetError: [Errno 104] Connection reset by peer

I think that the problem is that I'm using the existing retrieve method in the view for HEAD requests. But I also can't think that I should need to write a new method from scratch when retrieve already has the header I need.

How can I implement this? Thanks.

question from:https://stackoverflow.com/questions/65599348/how-to-create-route-and-view-for-head-http-verb-in-django-rest-framework

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I've found a solve and have a good theory of what the problem was. Looks like it was just the content-length header that was confusing the clients. Postman bugged out because it always expects a content-length of 0 in responses to HEAD requests (which, if I understand the RFC correctly, is a mistake on Postman's part), whereas curl and the server just got confused about whether the connection was still open because there was a non-zero content-length header but no content had come through. Again this is strange but I'm no expert so whatever. This is the implementation I got working (note that if I put an empty string in the Response object then I would still get the error. I have to JUST put a status code):

from django.http import Http404
class ResourceViewSet(viewsets.ModelViewSet):
    serializer_class = serializers.ResourceSerializer
    queryset = Resource.objects.all()
    lookup_field = 'value'

    def exists(self, request, *args, **kwargs):
        try:
            _ret = self.retrieve(request, *args, **kwargs)
            return Response(status=status.HTTP_200_OK)
        except Http404 as e:
            return Response(status=status.HTTP_404_NOT_FOUND)

In urls.py I direct head requests to the exists method.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

56.9k users

...