Django rest Framework пустой ответ с gunicorn, но работает с runserver - PullRequest
0 голосов
/ 31 марта 2020

Я пытаюсь реализовать аутентификацию Oauth2 с использованием django-oauth-toolkit, и обмен ключами работает, когда я использую встроенный сервер django. Однако, когда я использую Gunicorn, у меня есть пустой ответ. Все остальные конечные точки отлично работают с gunicorn:

команда gunicorn

gunicorn --bind 127.0.0.1:8000 api_name.wsgi

view.py


from rest_framework.response import Response
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import AllowAny

import requests


from .serializers import CreateUserSerializer


@api_view(['POST'])
@permission_classes([AllowAny])
def register(request):
    '''
    Registers user to the server. Input should be in the format:
    {"username": "username", "password": "1234abcd"}
    '''
    # Put the data from the request into the serializer
    serializer = CreateUserSerializer(data=request.data)
    # Validate the data
    if serializer.is_valid():
        # If it is valid, save the data (creates a user).
        serializer.save()
        # Then we get a token for the created user.
        # This could be done differentley
        r = requests.post('http://127.0.0.1:8000/o/token/', data={
                'grant_type': 'password',
                'username': request.data['username'],
                'password': request.data['password'],
                'client_id': get_client_id(),
                'client_secret': get_client_secret(),
            },
        )
        return Response(r.json())
    return Response(serializer.errors)


@api_view(['POST'])
@permission_classes([AllowAny])
def token(request):
    '''
    Gets tokens with username and password. Input should be in the format:
    {"username": "username", "password": "1234abcd"}
    '''
    r = requests.post('http://127.0.0.1:8000/o/token/', data={
            'grant_type': 'password',
            'username': request.data['username'],
            'password': request.data['password'],
            'client_id': get_client_id(),
            'client_secret': get_client_secret(),
            },
    )
    return Response(r.json())


@api_view(['POST'])
@permission_classes([AllowAny])
def refresh_token(request):
    '''
    Registers user to the server. Input should be in the format:
    {"refresh_token": "<token>"}
    '''
    r = requests.post('http://127.0.0.1:8000/o/token/', data={
            'grant_type': 'refresh_token',
            'refresh_token': request.data['refresh_token'],
            'client_id': get_client_id(),
            'client_secret': get_client_secret(),
        },
    )
    return Response(r.json())


@api_view(['POST'])
@permission_classes([AllowAny])
def revoke_token(request):
    '''
    Method to revoke tokens.
    {"token": "<token>"}
    '''
    r = requests.post( 'http://127.0.0.1:8000/o/revoke_token/', data={
            'token': request.data['token'],
            'client_id': get_client_id(),
            'client_secret': get_client_secret(),
        },
    )
    # If it goes well return sucess message (would be empty otherwise)
    if r.status_code == requests.codes.ok:
        return Response({'message': 'token revoked'}, r.status_code)
    # Return the error if it goes badly
    return Response(r.json(), r.status_code)

urls.py

from django.urls import path

from . import views

urlpatterns = [
    path('register/', views.register),
    path('token/', views.token),
    path('token/refresh/', views.refresh_token),
    path('token/revoke/', views.revoke_token),
]

когда я запускаю запрос:

curl -d "username=new_user&password=12345abcd" "127.0.0.1:8000/authentication/register/" -v

У меня есть ответы:

с django manage.py runserver :

*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 8000 (#0)
> POST /authentication/register/ HTTP/1.1
> Host: 127.0.0.1:8000
> User-Agent: curl/7.58.0
> Accept: */*
> Content-Length: 37
> Content-Type: application/x-www-form-urlencoded
> 
* upload completely sent off: 37 out of 37 bytes
< HTTP/1.1 200 OK
< Date: Tue, 31 Mar 2020 09:55:21 GMT
< Server: WSGIServer/0.2 CPython/3.6.2
< Content-Type: application/json
< Vary: Accept, Authorization, Cookie
< Allow: POST, OPTIONS
< X-Frame-Options: SAMEORIGIN
< Content-Length: 160
< 
* Connection #0 to host 127.0.0.1 left intact

{"access_token":"<access-token>","expires_in":36000,"token_type":"Bearer","scope":"read write","refresh_token":"<refresh-token>"}%

с gunicorn :

*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 8000 (#0)
> POST /authentication/register/ HTTP/1.1
> Host: 127.0.0.1:8000
> User-Agent: curl/7.58.0
> Accept: */*
> Content-Length: 37
> Content-Type: application/x-www-form-urlencoded
> 
* upload completely sent off: 37 out of 37 bytes
* Empty reply from server
* Connection #0 to host 127.0.0.1 left intact

curl: (52) Empty reply from server

журнал огнестрельного оружия

[2020-03-31 12:11:03 +0200] [3639] [INFO] Starting gunicorn 20.0.4
[2020-03-31 12:11:03 +0200] [3639] [INFO] Listening at: http://127.0.0.1:8000 (3639)
[2020-03-31 12:11:03 +0200] [3639] [INFO] Using worker: sync
[2020-03-31 12:11:03 +0200] [3686] [INFO] Booting worker with pid: 3686
[2020-03-31 12:11:46 +0200] [3639] [CRITICAL] WORKER TIMEOUT (pid:3686)

1 Ответ

1 голос
/ 31 марта 2020

Ах, я вижу, что происходит.

Вы используете gunicorn с одним работником, и ваше представление обращается к вашему собственному приложению ('http://127.0.0.1:8000/o/token/' <-> --bind 127.0.0.1:8000).

Хотя runserver по умолчанию является многопоточным, Gunicorn - нет, и пока он обрабатывает запрос, вы выполняете другой запрос в этом запросе ... Время тупика!

Либо включите больше работников для Gunicorn или рефакторинг вашего приложения таким образом, что ему не нужно делать внутренние запросы через HTTP.

...