【问题标题】:CORS issues with jQuery Dropzone and upload to ImgurjQuery Dropzone 的 CORS 问题并上传到 Imgur
【发布时间】:2014-10-15 03:55:06
【问题描述】:

我尝试使用 jQuery Dropzone 将图像上传到 Imgur 或任何其他域,但这不起作用。

这是我的放置区设置:

$("div.dropzone").dropzone
  success: -> console.log arguments
  paramName: "image"
  method: "post"
  maxFilesize: 2
  url: "https://api.imgur.com/3/upload"
  headers:
    Authorization: "Client-ID *************"

这不起作用。它说返回码是0。请求标头:

Host: api.imgur.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:31.0) Gecko/20100101 Firefox/31.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Origin: http://my.opencubes.io
Access-Control-Request-Method: POST
Access-Control-Request-Headers: authorization,cache-control,x-requested-with
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache

首先你可以看到cient id没有出现:(。但最大的问题是使用的方法是OPTIONS。响应头:

当我尝试将文件上传到我的另一个域时遇到同样的问题(dropzone 位于子域中)

在我看到的控制台中:

Une demande multi-origines (Cross-Origin Request) a été bloquée : la politique « Same Origin » ne permet pas de consulter la ressource distante située sur https://api.imgur.com/3/upload. Ceci peut être corrigé en déplaçant la ressource sur le même domaine ou en activant CORS.

可以翻译的

多源请求被阻止:“同源”策略不允许查看位于https://api.imgur.com/3/upload 的远程资源。这可以通过移动 samin 域上的资源或启用 CORS 来解决。

【问题讨论】:

  • OPTIONS 请求是一个普通请求:用于请求与 CORS 限制相关的权限(有关 CORS 的更多信息,请参见此处:toc-handling-a-not-so-simple-request) . api.imgur.com 是否只有一个请求?你能向我们展示所有请求/响应标头和内容到这个端点的请求吗?另外,检查您的控制台输出,看看是否没有问题。发送的数据是什么?请求中image 名称的值是多少?如果您真的想上传文件,请查看 AJAX 文件上传处理(谷歌)。
  • @pomeh 谢谢。问题是imgur 确实只有一个请求。这是唯一的一个。在控制台中,它说请求多源被阻止,我必须将它移动到同一个域:/。我想使用 Dropzone
  • 具体信息是什么?请求来自的确切域名和去向的域名是什么?
  • 确实,我在响应中没有看到任何 Access-Control-Allow-Origin 标头,因此它可能是相关的...但是无论如何您都无法更改它。这个标题不见了,看起来很奇怪。另外,请确保使用正确的Content-Typemultipart/form-data 来处理文件上传。最后,这是我在之前的评论中搞砸的链接:html5rocks.com/en/tutorials/cors/… 看看它以了解 CORS 的工作原理,也许您会在其中找到一些有用的信息。编辑:请求来自的确切域名是什么?
  • 我的错误。我将请求标头放在我的问题的响应标头中。固定的。域是my.opencubes.io,它不存在但在我的hosts 文件中

标签: javascript cors dropzone.js imgur


【解决方案1】:

OPTIONS 请求是一个普通请求:用于请求与 CORS 限制相关的权限。查看this page 以了解 CORS 的工作原理。

在您的情况下,这是一个纯粹的 CORS 相关问题。 OPTIONS 请求包含此标头:

Access-Control-Request-Headers: authorization,cache-control,x-requested-with

这意味着:我可以在我的跨域AJAX请求?

您得到的响应如下:

Access-Control-Allow-Headers :"Authorization, Content-Type, Accept, X-Mashape-Authorization"

这意味着:您只能使用这些标头:“Authorization”、“Content-Type”、“Accept”和“X-Mashape-Authorization”。

如您所见,“cache-control”和“x-requested-with未列出在允许列表中,导致浏览器拒绝请求。

我来到了 2 个显示这种行为的测试代码示例:

示例 1(工作)

var data = new FormData();
data.append('image', 'http://placehold.it/300x500');

var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://api.imgur.com/3/upload', true);
xhr.setRequestHeader('Authorization', 'Client-ID xxxxxxxxxx');
xhr.send(data);

以下是运行此代码时发送的预检请求标头(如 Firefox 30 devtools 所示,我已删除不相关的标头,例如 User-Agent、Accept ...):

以及对应的响应头

  • 访问控制允许来源:“*”
  • Access-Control-Allow-Methods :"GET, PUT, POST, DELETE, OPTIONS"
  • Access-Control-Allow-Headers :"授权、Content-Type、Accept、X-Mashape-Authorization"

在这里,我们可以看到我们提示访问“授权”头,并且服务器正在接受这个头,以及 POST 方法和任何原始 URL,因此满足 CORS 要求并且请求被允许浏览器。

示例 2(不起作用)

var data = new FormData();
data.append('image', 'http://placehold.it/300x500');

var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://api.imgur.com/3/upload', true);
xhr.setRequestHeader('Authorization', 'Client-ID xxxxxxxxxx');
// the only difference with the previous code is this line
xhr.setRequestHeader('Cache-Control', 'no-cache');
xhr.send(data);

预检请求的标头:

预检响应的标头(与示例 1 相同):

  • 访问控制允许来源:“*”
  • 访问控制允许方法:“GET、PUT、POST、DELETE、OPTIONS”
  • Access-Control-Allow-Headers:“授权、内容类型、接受、X-Mashape-Authorization”

这里的“Access-Control-Request-Headers”头提示访问“cache-control”,服务器不提供,所以CORS要求不满足,请求是被浏览器拒绝。

这里有一个 JSFiddle 引用不同的工作和不工作的演示来解决您的问题:http://jsfiddle.net/pomeh/Lfajnebh/。注意细节以了解发生了什么,很少有 cmets,但他们在这里强调代码中最棘手的部分。

作为奖励,我已向 DropZone 的 GitHub 存储库发送了一个拉取请求以解决此问题 (https://github.com/enyo/dropzone/pull/685),它允许您删除 DropZone 的预定义标头。试试看:

var myDropzone = new Dropzone('.dropzone', {
    //...
    headers: {
        'Authorization': authorizationHeader,
        // remove Cache-Control and X-Requested-With
        // to be sent along with the request
        'Cache-Control': null,
        'X-Requested-With': null
    }
});

上面的代码应该适用于我的补丁版本 (https://github.com/pomeh/dropzone/commit/f0063db6e5697888582421865840258dec1ffdc1),而上面的代码不应该:

var myDropzone = new Dropzone('.dropzone', {
    //...
    headers: {
        'Authorization': authorizationHeader,
        // remove Cache-Control and X-Requested-With
        // to be sent along with the request
    }
});

【讨论】:

  • 添加标头 'Cache-Control': null, 'X-Requested-With': null 工作正常
【解决方案2】:

您遇到了浏览器的same-origin security policy。每个浏览器都有一个; “起源”基本上是指“同一地点”。我在 example.com 上的 JavaScript 可以访问它在 example.com 上喜欢的任何内容,但不允许从 demo.com、example.net 或 api.example.com 读取任何内容。他们来自不同的起源。 Here's a table of what counts as the same origin.

没有它,我可以编写一个网页来窃取你所有的 gmail 和私人 Facebook 照片。我的恶意 JavaScript 会向 gmail.com 和 facebook.com 发出网络请求,找到指向您的电子邮件和照片的链接,也加载该数据,然后将其发送到我自己的服务器。

但有些服务(如 API)被设计为可供其他服务访问。这就是CORS 的用武之地——跨域资源共享。 Web 服务可以使用 CORS 告诉浏览器允许从脚本访问是可以的。如果您想通过提交到您自己的服务器来测试您的代码,请确保您的服务器是sending the required HTTP response headers

如果您在本地开发,还必须确保从 Web 服务器进行测试 - 以 http:// 开头的地址,而不是 file://。该协议是源的一部分,因此您无法从文件 URL 提交到 http 端点。


CORS 有不同类型的请求。一些请求被认为是简单请求,但其他请求 - 带有自定义标头的请求 - 需要“preflighting”。这意味着浏览器将向服务器发送一个请求,说“这个请求是否适用于 CORS?”在发送实际请求之前使用 HTTP OPTIONS 方法。任何带有自定义标头的请求都需要预检; 那是你的 HTTP OPTIONS 来自哪里。 jQuery adds a custom X-Requested-With header to AJAX requests,所以即使你没有添加那些你仍然会在实际 POST 之前看到 Options 请求。

从您的屏幕截图中,看起来 Imgur 将允许您的 HTTP POST 方法。让我们继续弄清楚为什么这不起作用。


我们使用的是Imgur image upload API endpoint。这有一个必需的参数(image),如果我们只想匿名上传,我们只需要a registered app。 upload 方法让我们发送一个简单的 URL 到一张图片进行上传,所以让我们尝试向 Imgur 发出一个 AJAX 请求:

$.ajax
  success: (data) -> console.log data
  type: "POST"
  data: 
    image: "http://placehold.it/300x500"
  url: "https://api.imgur.com/3/upload"
  headers:
    Authorization: "Client-ID *************" # Don't forget to put your actual Client-ID here!

下一步是尝试使用Filereader API 从表单中读取文件,然后发送。这是一个 CoffeeScript 提交处理程序:

$('#file-form').submit (ev) -> 
  ev.preventDefault()
  file = $('#file-form input[name=file]').get(0).files[0] 
  $.ajax
    success: (data) -> console.log data
    type: "POST"
    data: 
      image: file
    url: "https://api.imgur.com/3/upload"
    headers:
      Authorization: "Client-ID *************"

最后,我们可以尝试使用Dropzone 来实现同样的效果:

$("div.dropzone").dropzone
  success: (file, response) -> 
    console.log file
    console.log response
  paramName: "image"
  method: "post"
  maxFilesize: 2
  url: "https://api.imgur.com/3/upload"
  headers:
    "Authorization": "Client-ID *************"

Dropzone success 回调有两个参数:上传的文件和来自服务器的响应。您可能对后者最感兴趣; Imgur sends back an id and a link parameter on success 可以用来向用户展示他们新上传的图片。


有一个使用来自 JavaScript available on Github here 的 Imgur API 的示例项目。

【讨论】:

    猜你喜欢
    • 2014-06-18
    • 2017-09-09
    • 2010-12-21
    • 1970-01-01
    • 1970-01-01
    • 2021-08-04
    • 1970-01-01
    • 2014-05-09
    • 2013-12-29
    相关资源
    最近更新 更多