3

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

Единственная деталь, которую я не могу сделать, это загрузка файлов. Я использую 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)' ]

В производстве, я считаю, исправление будет configure CORS on my bucket, но я не уверен. Однако у меня есть no Идея, как настроить локальный сервер разработки для этого, чтобы я мог протестировать общий поток данных до развертывания.

Вот 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 есть (кажется) вне моего контроля, в том числе добавление заголовков.

+0

Когда я говорю «это работает при запуске из того же хозяина», я должен уточнить. Детали обработки сообщений и ответов немного отличаются, поскольку предыдущее приложение не использовало AngularJS; возможно, что я также делаю другие вещи немного неправильно здесь, но я не могу устранить это, пока не решит проблему CORS. – seawolf

+0

Выполняет ли обработчик для 'url' отправку заголовков CORS? Вот пример того, что вам нужно сделать, чтобы заставить его работать: https://github.com/GoogleCloudPlatform/appengine-python-blobstore-cors-upload/blob/master/main.py –

+0

почему бы не прямо ПОСТ-файл в formData к конечной точке, а не сначала получить, а затем опубликовать? Подобно 'var input = $ ('selector'); var data = new FormData(); data.append ('name', input.name); data.append ('type', input.type); data.append (input.name, input.files [0]); $ .ajax ({ URL: 'URL', тип: 'POST', ProcessData: ложь, CONTENTTYPE: ложь, // значение для jqXHR данных: данные} .done() ' – dliu

ответ

1

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

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

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

Эта конкретная настройка возможна только для статических обработчиков файлов (см. [Обработчики статических файлов] (https://cloud.google.com/appengine/docs/python/config/appconfig)). Я очень надеялся, когда впервые обнаружил, что несколько дней назад, но это не помогает в этом случае, насколько я могу судить. – seawolf

0

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

Например, 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

+1

Это уже сделано и работает на всех остальных конечных точках. Это единственная конечная точка, которая находится за пределами моей кодовой базы (обрабатывается внешней службой в среде App Engine), которая не предоставляет эти заголовки. – seawolf