XMLHttpRequest 错误

Posted

技术标签:

【中文标题】XMLHttpRequest 错误【英文标题】:XMLHttpRequest error 【发布时间】:2016-06-18 18:07:08 【问题描述】:

我有一个 Google App Engine 应用程序,当一切都在一台主机上运行时,它在生产环境中运行良好,而当网络应用程序在另一台主机上运行时,它主要运行良好。所有发往/来自服务器的查询(GETPOSTPUTDELETE)都按预期运行。这向我表明,我在整个系统中正确配置了所有 CORS(我在几周前进行了那场战斗并且一切都解决了)。

我唯一不能做的是文件上传。我正在使用djangodjangoappenginedjango-cors-headersfiletransfers,最终结果是从远程服务器运行时我无法上传文件,但其他一切工作正常。在 Chrome 的 javascript 控制台中,我看到以下错误:

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 为 8080 端口上的 API 提供服务 grunt serve 在端口 9000 上为客户端应用程序提供服务 CORS 设置: 开发:CORS_ORIGIN_ALLOW_ALL = True 制作:CORS_ORIGIN_WHITELIST = [ '(app.domain.com for my app)' ]

在生产中,我相信修复将是configure CORS on my bucket,但我并不肯定。但是,我知道如何为此配置本地开发服务器,以便在部署之前测试整体数据流。

以下是最终失败的 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 组装我的上传表单,但我过去从未找到这样做的方法。

--- 更新到添加 ---

澄清一点,导致此错误的端点并不直接在我的应用程序中,它位于由单独的 Google 服务处理的 URL 上。给我 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/&lt;one-time key&gt;,在该 URL 上发生的一切(似乎)都超出了我的控制范围,包括添加标题。

【问题讨论】:

当我说“这在从同一主机运行时有效”时,我应该澄清一下。由于之前的应用程序没有使用 AngularJS,因此发布和响应处理的细节略有不同;有可能我在这里也做错了其他事情,但在解决 CORS 问题之前我无法解决任何问题。 url 的处理程序是否发送 CORS 标头?下面是一个例子,说明你需要做什么才能让它工作:github.com/GoogleCloudPlatform/… 为什么不直接将formData中的文件POST到端点,而不是先get再post呢?喜欢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', type: 'POST', processData: false, contentType: false, // important for jqXHR data: data.done() 端点 URL 由数据存储即时创建,并且只能使用一次,因此我必须从服务器(GET)检索 URL,然后使用 POST 到该端点要上传的文件。 我从来没有找到一个好的解决方案。相反,我在 AppEngine 项目上创建了一个表单,它有几个 JavaScript 挂钩来指示重要事件(已加载、选择文件、上传完成等),然后我将该表单作为 IFrame 嵌入到客户端应用程序中并监听这些事件.它很丑,但它可以完成工作。 【参考方案1】:

一种方法是在 app.yaml 中为特定 url 设置 http 标头

例如:

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

【讨论】:

此特定设置仅适用于静态文件处理程序(请参阅Static File Handlers)。几天前我第一次发现它时,我很有希望,但据我所知,它在这种情况下没有帮助。【参考方案2】:

您的 http 处理程序必须具有用于将 cors 标头发送到浏览器的 OPTIONS 方法。

例如; Chrome 总是在 PUT 请求检查 CORS 标头之前向同一 URL 发送一个 OPTIONS 请求。如果浏览器无法得到 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

【讨论】:

这已经完成,并且适用于所有其他端点。这是我的代码库之外的单个端点(由 App Engine 环境中的外部服务处理),没有提供这些标头。

以上是关于XMLHttpRequest 错误的主要内容,如果未能解决你的问题,请参考以下文章

XMLHttpRequest (Ajax) 错误

XMLHTTPRequest 错误:不推荐使用主线程上的同步 XMLHttpRequest ...(SoundCloud API)

axios 授权标头/CORS 错误

XMLHttpRequest:网络错误访问被拒绝

错误:使用天气 API 时出现 XMLHttpRequest 错误

如何检测 Chrome 应用程序中的 XMLHttpRequest 错误