Бэкенд Django на порту 8083 не может обработать AJAX CORS POST запрос, отправленный с веб-страницы gulp на порту 8081

На Linux Debian Bullseye я запускаю HTML-сервер gulp на порту 8081 и бэкенд Django на порту 8083. Я пытаюсь отправить относительно большой JSON документ со статической страницы, используя функцию AJAX JQuery. После правильной настройки модуля django-cors-headers, с MIDDLEWARE = [ "corsheaders.middleware.CorsMiddleware" ], CORS_ALLOWED_ORIGINS и CSRF_TRUSTED_ORIGINS в settings.py, я создал следующее HTML представление в views.py, с декоратором @csrf_exempt на месте, поскольку я запускаю все на localhost:

from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def processOrder(request):
   leasing_order_unicode = request.body.decode("utf-8")
   print(request.POST.__dict__)
   print(request.POST["leasing_order"])
   return HttpResponse(leasing_order_unicode, headers={ "Access-Control-Allow-Origin": "http://localhost:8081", "Content-Type": "application/json" })

Затем я добавил его в urls.py следующим образом:

path("processorder", processOrder, name="processorder")

Я ожидаю, что мое представление Django сможет получить доступ к строке JSON с помощью request.POST["leasing_order"]. <<<Вместо этого, я получаю ошибки и сбои при попытке доступа к ней. Пусть

Пусть serializedata() будет функцией, которая позаботится о сборе всех моих локальных данных в объект и последующей их сериализации. Если я отправлю данные формы с кодировкой multipart/form-data следующим образом:

export function sendOrder_multipart()
{
   let finalorder = serializedata();
   let finalorder_postdata = new FormData();
   finalorder_postdata.append("leasing_order", finalorder);
   $.ajax({ method: "POST", url: "http://localhost:8083/orderstable/processorder",
      data: finalorder_postdata, processData: false, contentType: "multipart/form-data" });
}

На выходе консоли моего Django backend'а я получаю следующую ошибку:

Bad request (Unable to parse request body): /orderstable/processorder
Traceback (most recent call last):
  File "<project path>/lib/python3.9/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "<project path>/lib/python3.9/site-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "<project path>/lib/python3.9/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "<project path>/<website>/orderstable/views.py", line 54, in processOrder
    print(request.POST.__dict__)
  File "<project path>/lib/python3.9/site-packages/django/core/handlers/wsgi.py", line 102, in _get_post
    self._load_post_and_files()
  File "<project path>/lib/python3.9/site-packages/django/http/request.py", line 328, in _load_post_and_files
    self._post, self._files = self.parse_file_upload(self.META, data)
  File "<project path>/lib/python3.9/site-packages/django/http/request.py", line 287, in parse_file_upload
    parser = MultiPartParser(META, post_data, self.upload_handlers, self.encoding)
  File "<project path>/lib/python3.9/site-packages/django/http/multipartparser.py", line 76, in __init__
    raise MultiPartParserError('Invalid boundary in multipart: %s' % force_str(boundary))
django.http.multipartparser.MultiPartParserError: Invalid boundary in multipart: None
[17/Dec/2021 20:29:11] "POST /orderstable/processorder HTTP/1.1" 400 143

Если я настрою функцию фронтенда Javascript так, чтобы она не использовала кодировку multipart/form-data, например, так:

function sendOrder_nomultipart()
{
   let finalorder = serializedata();
   let finalorder_postdata = new FormData();
   finalorder_postdata.append("leasing_order", finalorder);
   $.ajax({ method: "POST", url: "http://localhost:8083/orderstable/processorder",
      data: finalorder_postdata, processData: false });
}

Я получаю немного другой результат, но по-прежнему не могу получить доступ к моей строке через request.POST:

{'_encoding': 'UTF-8', '_mutable': False}
Internal Server Error: /orderstable/processorder
Traceback (most recent call last):
  File "<project root>/lib/python3.9/site-packages/django/utils/datastructures.py", line 83, in __getitem__
    list_ = super().__getitem__(key)
KeyError: 'leasing_order'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<project root>/lib/python3.9/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "<project root>/lib/python3.9/site-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "<project root>/lib/python3.9/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "<project root>/<website>/orderstable/views.py", line 55, in processOrder
    print(request.POST["leasing_order"])
  File "<project root>/lib/python3.9/site-packages/django/utils/datastructures.py", line 85, in __getitem__
    raise MultiValueDictKeyError(key)
django.utils.datastructures.MultiValueDictKeyError: 'leasing_order'
[17/Dec/2021 20:35:59] "POST /orderstable/processorder HTTP/1.1" 500 106954

Разумеется, ресурс на порту 8083 и другой на порту 8081 рассматриваются веб-браузерами как разные ресурсы.

Ресурс на порту 8081 не имеет права отправлять небезопасные запросы типа POST на порт 8083, если последний не разрешает это.

Django не имеет встроенной поддержки Cors, поэтому вам придется установить и настроить пакет под названием django-cors-headers.

Я нашел решение после воспроизведения этой проблемы с минимальным тестовым примером. Чтобы решить эту проблему, вы должны передать данные POST в $.ajax() как простой объект вместо использования объекта FormData(), и опустить поля contentType и processData объекта конфигурации.

Код, который сработал:

function sendOrder_thegoodone()
{
   let finalorder = serializedata();
   let finalorder_obj = { leasing_order: finalorder };
   $.ajax(
   { 
      method: "POST", 
      url: "http://localhost:8083/orderstable/processorder",
      data: finalorder_obj
   });
}

Я нашел решение после воспроизведения этой проблемы с минимальным тестовым примером. Чтобы решить эту проблему, вы должны передать данные POST в $.ajax() как простой объект вместо использования объекта FormData(), и опустить поля contentType и processData объекта конфигурации.

Код, который сработал:

function sendOrder_thegoodone()
{
   let finalorder = serializedata();
   let finalorder_obj = { leasing_order: finalorder };
   $.ajax(
   { 
      method: "POST", 
      url: "http://localhost:8083/orderstable/processorder",
      data: finalorder_obj
   });
}
Вернуться на верх