javascript jQuery Dropzone 的 CORS 问题并上传到 Imgur

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25427627/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 04:30:09  来源:igfitidea点击:

CORS issues with jQuery Dropzone and upload to Imgur

javascriptcorsdropzone.jsimgur

提问by Vinz243

I tried to use jQuery Dropzone to upload an image to Imgur or any other domain but that's not working.

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

This is my dropzone setup:

这是我的 dropzone 设置:

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

This doesn't work. It says that return code is 0. The request headers:

这不起作用。它说返回码为 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

First as you can see the cient id doesn't appear :(. But the big problem is that the method used is OPTIONS. The response headers:

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

headers

标题

I have the same problem when I try to upload the file to another domain of mine (the dropzone is located in a subdomain)

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

In the console I see:

在控制台中,我看到:

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.

Which can be translated by

可以翻译成

A multi-origin request was blocked: the policy "Same origin" does not allow to see remote resource located in https://api.imgur.com/3/upload. this an be fixed by moving the resource on the samin domain or by enabling CORS.

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

回答by pomeh

The OPTIONS request is a normal request: this is used to ask for permissions relative to CORS restrictions. Have a look to this pageto understand how CORS work under the hood.

OPTIONS 请求是一个普通请求:这用于请求与 CORS 限制相关的权限。查看此页面以了解 CORS 是如何在幕后工作的。

In your case, this is a pure CORS related issue. The OPTIONS request contains this header:

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

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

Which means: can I use "authorization", "cache-control" and "x-requested-with" headers in my cross-domain AJAX request ?

这意味着:我可以在跨域 AJAX 请求中使用“授权”、“缓存控制”和“ x-requested-with”标头吗?

The response you get is the following:

您得到的回复如下:

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

Which means: you're allowed to use those headers only: "Authorization", "Content-Type", "Accept", and "X-Mashape-Authorization".

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

As you can see, "cache-control" and "x-requested-with" are not listedin the allowed list, causing the browser to reject the request.

可以看到,“ cache-control”和“ x-requested-with没有列在允许列表中,导致浏览器拒绝请求。

I've come to 2 test code sample which show this behavior:

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

Example 1 (working)

示例 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);

Here are the preflight request's headers sent when running this code (as shown by Firefox 30 devtools, and I've removed unrelated headers such as User-Agent, Accept ...):

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

And the corresponding response's headers

以及相应的响应头

  • access-control-allow-origin :"*"
  • Access-Control-Allow-Methods :"GET, PUT, POST, DELETE, OPTIONS"
  • Access-Control-Allow-Headers :"Authorization, Content-Type, Accept, X-Mashape-Authorization"
  • 访问控制允许来源:“*”
  • 访问控制允许方法:“GET、PUT、POST、DELETE、OPTIONS”
  • Access-Control-Allow-Headers:“授权,内容类型,接受,X-Mashape-授权”

Here, we can see that we prompt access to the "authorization" header, and the server is accepting this header, allong with the POST method and any origin URL, so the CORS requirements are satisfied and the request is allowed by the browser.

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

Example 2 (not working)

示例 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);

Preflight request's headers:

预检请求的标头:

Preflight response's headers (which is the same as in example 1):

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

  • access-control-allow-origin :"*"
  • Access-Control-Allow-Methods :"GET, PUT, POST, DELETE, OPTIONS"
  • Access-Control-Allow-Headers :"Authorization, Content-Type, Accept, X-Mashape-Authorization"
  • 访问控制允许来源:“*”
  • 访问控制允许方法:“GET、PUT、POST、DELETE、OPTIONS”
  • Access-Control-Allow-Headers:“授权,内容类型,接受,X-Mashape-授权”

Here, the "Access-Control-Request-Headers" header prompt access for "cache-control", which the server does not provide, so the CORS requirements are not satisfiedand the request is rejected by the browser.

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

Here's a JSFiddle referencing different working and not working demos for your problem: http://jsfiddle.net/pomeh/Lfajnebh/. Pay attention to details to understand what's going on, there is few comments but they are here to emphasis trickiest parts of the code.

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

As a bonus, I've sent a pull request to DropZone's GitHub repository to fix this problem (https://github.com/enyo/dropzone/pull/685) which allows you to remove pref-defined headers by DropZone. Give it a try:

作为奖励,我已经向 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
    }
});

The code above should work with my patched version (https://github.com/pomeh/dropzone/commit/f0063db6e5697888582421865840258dec1ffdc1), whereas the code above should not:

上面的代码应该适用于我的补丁版本(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
    }
});

回答by Alex P

You're running into the browser's same-origin security policy. Every browser has one; "origin" basically means "the same site". my JavaScript on example.com can access whatever it likes on example.com, but it's not allowed to read anything from demonstration.com, example.net, or api.example.com. They're from a different origin. Here's a table of what counts as the same origin.

您遇到了浏览器的同源安全策略。每个浏览器都有一个;“起源”基本上意味着“同一站点”。我在 example.com 上的 JavaScript 可以访问它在 example.com 上喜欢的任何内容,但不允许从 demo.com、example.net 或 api.example.com 读取任何内容。他们来自不同的起源。这是一个表,说明了什么是相同的起源

Without it, I could write a web page that steals all your gmail and private Facebook photos. My malicious JavaScript would make web requests to gmail.com and facebook.com, find the links to your emails & photos, load that data too, and then send it off to my own server.

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

But some services, like APIs, are designed to be accessed by other services. That's where CORScomes in - Cross-Origin Resource Sharing. Web services can use CORS to tell browsers that it's fine to allow access from scripts. If you want to test your code by submitting to your own server, make sure your server is sending the required HTTP response headers.

但是某些服务(例如 API)旨在供其他服务访问。这就是CORS 的用武之地——跨域资源共享。Web 服务可以使用 CORS 来告诉浏览器允许从脚本访问是可以的。如果您想通过提交到您自己的服务器来测试您的代码,请确保您的服务器正在发送所需的 HTTP 响应标头

If you're developing locally, you must also be sure to test from a web server - an address beginning with http://, not file://. The protocol is part of the origin, so you can't submit to an http endpoint from a file URL.

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



CORS has different types of requests. Some requests are considered simple requests, but others - requests with custom headers - require "preflighting". This means the browser will send a request to the server saying "Is this request OK for CORS?" using the HTTP OPTIONSmethod before sending the actual request. Any request with custom headers requires preflighting; that'swhere your HTTP OPTIONSis coming from. jQuery adds a custom X-Requested-Withheader to AJAX requests, so even if you hadn't added those you'd still see that Optionsrequest before the actual POST.

CORS 有不同类型的请求。一些请求被认为是简单的请求,但其他请求 - 带有自定义标头的请求 - 需要“预检”。这意味着浏览器会向服务器发送一个请求,说“这个请求对于 CORS 是否合适?” OPTIONS在发送实际请求之前使用 HTTP方法。任何带有自定义标头的请求都需要预检;就是您的 HTTPOPTIONS的来源。jQuery向 AJAX 请求添加了一个自定义X-Requested-With标头,因此即使您没有添加这些标头,您仍然会Options在实际 POST 之前看到该请求。

From your screenshots, it looks like Imgur is going to allow your HTTP POSTmethod. Let's move on to figuring out why that's not working.

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



We're using the Imgur image upload API endpoint. This has one required parameter (image), and if we only want anonymous uploads all we need is a registered app. The upload method lets us send a simple URL to an image for upload, so let's try making an AJAX request to Imgur:

我们正在使用Imgur 图片上传 API 端点。这有一个必需的参数 ( image),如果我们只想要匿名上传,我们只需要一个注册的应用程序。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!

The next step is to try using the Filereader APIto read the file from the form, and send that. Here's a CoffeeScript submit handler for that:

下一步是尝试使用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 *************"

Finally, we can try using Dropzoneto achieve the same thing:

最后,我们可以尝试使用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 *************"

The Dropzone successcallback gets two arguments: the file that was uploaded, and the response from the server. You'll probably be most interested in the latter; Imgur sends back an idand a linkparameter on successthat you can use to show the user their newly-uploaded image.

Dropzonesuccess回调有两个参数:上传的文件和来自服务器的响应。您可能对后者最感兴趣;Imgur 返回一个idlink成功参数,您可以使用它向用户显示他们新上传的图像。



There's an example project for using the Imgur API from JavaScript available on Github here.

在 Github 上有一个使用来自 JavaScript 的 Imgur API 的示例项目。