Ошибка XMLHttpRequest

У меня есть приложение Google App Engine, которое отлично работает на производстве, когда все работает на одном хосте, и в основном работает, когда веб-приложение работает на отдельном хосте. Все запросы к / с сервера (GET, POST, PUT, DELETE) ведут себя как ожидалось. Это указывает мне на то, что у меня все CORS настроено правильно во всей системе (я сражался в этой битве несколько недель назад и все получилось).

Единственная часть, которую я не могу сделать - это загрузка файлов. я использую django, djangoappengine, django-cors-headers, а также filetransfersи в результате все, что я не могу загрузить файлы при запуске с удаленного сервера, но все остальное работает правильно. В консоли JavaScript в Chrome я вижу следующую ошибку:

XMLHttpRequest cannot load http://localhost:8080/_ah/upload/ahl...<truncated>.
Response to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:9000' is therefore not allowed
access. The response had HTTP status code 405.

Это явно ошибка CORS, поэтому я примерно знаю, что должно произойти. За исключением того, что я не могу понять, как внести необходимые изменения в мою конфигурацию, чтобы преодолеть это.

Вот моя общая установка:

  • dev_appserver.py обслуживающий API через порт 8080
  • grunt serve обслуживание клиентского приложения на порту 9000
  • Настройки CORS:
    • развитие: CORS_ORIGIN_ALLOW_ALL = True
    • производство: CORS_ORIGIN_WHITELIST = [ '(app.domain.com for my app)' ]

Я полагаю, что в процессе производства исправление будет заключаться в настройке CORS на моем ведре, но я не уверен. Однако я не знаю, как настроить для этого локальный сервер разработки, чтобы я мог проверить общий поток данных перед развертыванием.

Вот JavaScript, который в конечном итоге не работает (приложение использует AngularJS):

var form = angular.element('#media-form');
var data = new FormData(form);

// have the API return a URL using prepare_upload in
// filetransfers module to upload to:
var uploadActionUrl = https://api.domain.com/upload_url/';
$http.get(uploadActionUrl)
  .then(function(response) {
    // I get here with no problem
    $http.post(response.data.action, formData)
      .then(function(response) {
        console.log('got:', response);
      }, function(error) {
        console.log('upload error:', error); // <- this is where I end up
      });
  }, function(error) {
    console.log('get upload URL error:', error);
  });

Опять же, код, очень похожий на этот, работает правильно при запуске с того же хоста (поэтому сам API работает правильно), и (что важно) все методы HTTP работают на всех конечных точках, кроме загрузки моего файла, поэтому сам CORS настроен правильно для взаимодействие с App Engine. Это только часть загрузки файла, которая не работает.

Мне приходит в голову, что, возможно, исправление включает сборку моей формы для загрузки с использованием JSON вместо FormData, но я никогда не нашел способ сделать это в прошлом.

--- ОБНОВЛЕНО, ЧТОБЫ ДОБАВИТЬ ---

В качестве пояснения: конечная точка, которая вызывает эту ошибку, не находится непосредственно в моем приложении, а находится по URL-адресу, обрабатываемому отдельной службой Google. Код, который дает мне URL-адрес:

from google.appengine.ext.blobstore import create_upload_url

def prepare_upload(request, url, **kwargs):
    return create_upload_url(
        url,
        gs_bucket_name = settings.GOOGLE_CLOUD_STORAGE_BUCKET
    ), {}

URL, который я получаю, имеет вид /_ah/upload/<one-time key>и все, что происходит по этому URL-адресу (кажется) вне моего контроля, включая добавление заголовков.

2 ответа

Один из способов - установить заголовки http для определенного URL в вашем app.yaml

Так, например:

handlers:
- url: /_ah/upload....
  ...
  http_headers:
    Access-Control-Allow-Origin: http://localhost:9000

Ваши обработчики http должны иметь метод OPTIONS для отправки заголовков cors в браузер.

Например; Chrome всегда отправляет запрос OPTIONS на один и тот же URL-адрес, прежде чем запросы PUT для проверки заголовков CORS. Если браузер не может получить ответ на запрос OPTIONS, cors завершится ошибкой.

Проверьте этот пример движка приложения webapp2.

class BaseRestHandler(webapp2.RequestHandler):
    def options(self, *args, **kwargs):
        self.response.headers['Access-Control-Allow-Origin'] = '*'
        self.response.headers['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept'
        self.response.headers['Access-Control-Allow-Methods'] = 'POST, GET, PUT, DELETE'

https://en.wikipedia.org/wiki/Cross-origin_resource_sharing

Другие вопросы по тегам