Django+Angular CORS не работает с POST
Мое приложение Angular4 (работает на http://127.0.0.1:4200
сервер разработки) должен иметь доступ к бэкэнду REST django в сети. Бэкэнд находится под моим контролем и доступен только через HTTPS (работает Apache, который туннелирует запрос на сервер gunicorn, работающий на внутренний порт). Допустим, это https://example.com/
, По историческим причинам вход пользователя в систему осуществляется с помощью сеансов, потому что я хочу, чтобы пользователи могли также использовать интерфейс администратора Django после входа в систему. Рабочий процесс выглядит следующим образом:
- Пользователи открываются
http://127.0.0.1:4200
Я выполняю запрос GEThttps://example.com/REST/is_logged_in
который возвращает 403, когда пользователь еще не вошел в систему через сеансы, 200 в противном случае. В первом случае пользователь перенаправляется наhttps://example.com/login/
, созданный механизмом шаблонов Django, позволяющий пользователю войти в систему. После входа пользователь перенаправляется наhttp://127.0.0.1:4200
- При нажатии на какую-либо кнопку в моем Angular UI выполняется запрос POST. Этот пост-запрос завершается с ошибкой 403, даже несмотря на то, что в предварительном запросе OPTIONS явно указывается POST как разрешенные действия.
Вот моя конфигурация CORS в Django:
NG_APP_ABSOLUTE_URL = 'http://127.0.0.1:4200'
# adapt Django's to Angular's presumed XSRF cookie/header names
CSRF_COOKIE_NAME = "XSRF-TOKEN"
CSRF_HEADER_NAME = "HTTP_X_XSRF_TOKEN"
CORS_ORIGIN_WHITELIST = (
urlparse(NG_APP_ABSOLUTE_URL).netloc
)
CSRF_TRUSTED_ORIGINS = (
urlparse(NG_APP_ABSOLUTE_URL).netloc
)
CORS_ALLOW_HEADERS = default_headers + (
'x-xsrf-token',
)
CORS_ALLOW_CREDENTIALS = True
Вот что сообщает Chrome для (успешного, 200) первого запроса REST GET, чтобы проверить, вошел ли пользователь в систему (после того, как он успешно это сделал) в ответе:
Access-Control-Allow-Credentials:true
Access-Control-Allow-Origin:http://127.0.0.1:4200
Allow:GET, HEAD, OPTIONS
Connection:close
Content-Type:application/json
Date:Wed, 26 Apr 2017 15:09:26 GMT
Server:gunicorn/19.6.0
Set-Cookie:XSRF-TOKEN=...; expires=Wed, 25-Apr-2018 15:09:26 GMT; Max-Age=31449600; Path=/
Transfer-Encoding:chunked
Vary:Accept,Cookie,Origin
X-Frame-Options:SAMEORIGIN
Соответствующий запрос имел это:
Cookie:sessionid=...; XSRF-TOKEN=...
Host:example.com
Origin:http://127.0.0.1:4200
Referer:http://127.0.0.1:4200/
Теперь к актуальной проблеме:
Предполетный запрос:
Request URL:https://example.com/REST/change_user_data/
Request Method:OPTIONS
Status Code:200 OK
Access-Control-Request-Headers:content-type
Access-Control-Request-Method:POST
Connection:keep-alive
Host:example.com
Origin:http://127.0.0.1:4200
Referer:http://127.0.0.1:4200/dashboard/account
Предполетный ответ:
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:accept, accept-encoding, authorization, content-type, dnt, origin, user-agent, x-csrftoken, x-requested-with, x-xsrf-token
Access-Control-Allow-Methods:DELETE, GET, OPTIONS, PATCH, POST, PUT
Access-Control-Allow-Origin:http://127.0.0.1:4200
Access-Control-Max-Age:86400
Connection:close
Content-Length:0
Content-Type:text/html; charset=utf-8
Date:Wed, 26 Apr 2017 15:36:56 GMT
Server:gunicorn/19.6.0
Vary:Origin
X-Frame-Options:SAMEORIGIN
Теперь мой неудачный (403) POST-запрос:
Accept:application/json
Accept-Encoding:gzip, deflate, br
Accept-Language:de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
Connection:keep-alive
Content-Length:60
Content-Type:application/json
Cookie:sessionid=...; XSRF-TOKEN=...
Host:example.com
Origin:http://127.0.0.1:4200
Referer:http://127.0.0.1:4200/dashboard/account
Заголовки ответа:
HTTP/1.1 403 Forbidden
Date: Wed, 26 Apr 2017 15:36:56 GMT
Server: gunicorn/19.6.0
Vary: Accept,Cookie,Origin
X-Frame-Options: SAMEORIGIN
Content-Type: application/json
Access-Control-Allow-Credentials: true
Allow: POST, OPTIONS
Access-Control-Allow-Origin: http://127.0.0.1:4200
Set-Cookie: XSRF-TOKEN=...; expires=Wed, 25-Apr-2018 15:36:56 GMT; Max-Age=31449600; Path=/
Connection: close
Transfer-Encoding: chunked
Почему этот запрос не работает? Это имеет мало смысла для меня!
С наилучшими пожеланиями!
1 ответ
У меня была такая же проблема, когда я пытался отправить запрос POST в Django (порт 8000) из моего Angular CLI (порт 4200). Я подумал, что это проблема Django, поэтому я установил пакет cors, однако "проблема" связана с браузером (на самом деле это не проблема, это проблема безопасности, см. Здесь). В любом случае, я решил проблему с добавлением прокси-правила для моего Angular CLI следующим образом:
- Во-первых, вместо того, чтобы отправлять мои запросы по http://localhost:8000/api/..., отправляйте их в / api / (то есть на мой сервер ng, работающий на порту 4200).
- Затем я добавил в свой проект Angular файл с именем "proxy.conf.json" со следующим содержимым:
{
"/api": {
"target": "http://localhost:8000",
"secure": false
}
}
- Наконец, запустите ваш сервер ng с флагом "--proxy-config":
ng serve --watch --proxy-config proxy.conf.json
Все запросы API будут отправлены на порт 4200, и Angular внутренне перенаправит их на Django, избегая проблемы CORS. Обратите внимание, что это действительно только для разработки и не будет использоваться, когда вы создаете код приложения и добавляете его как статический код вашего сервера Django.
Наконец, с этим решением мне больше не понадобился модуль python для cors, чтобы вы могли его удалить.