У меня есть приложение 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 на порту 8080grunt 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 есть (кажется) вне моего контроля, в том числе добавление заголовков.
Когда я говорю «это работает при запуске из того же хозяина», я должен уточнить. Детали обработки сообщений и ответов немного отличаются, поскольку предыдущее приложение не использовало AngularJS; возможно, что я также делаю другие вещи немного неправильно здесь, но я не могу устранить это, пока не решит проблему CORS. – seawolf
Выполняет ли обработчик для 'url' отправку заголовков CORS? Вот пример того, что вам нужно сделать, чтобы заставить его работать: https://github.com/GoogleCloudPlatform/appengine-python-blobstore-cors-upload/blob/master/main.py –
почему бы не прямо ПОСТ-файл в 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