简体   繁体   English

CORS与jQuery Dropzone问题并上传到Imgur

[英]CORS issues with jQuery Dropzone and upload to Imgur

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 。响应头:

头

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 . 多源请求被阻止:策略“Same origin”不允许查看位于https://api.imgur.com/3/upload的远程资源。 this an be fixed by moving the resource on the samin domain or by enabling CORS. 这可以通过在samin域上移动资源或启用CORS来修复。

The OPTIONS request is a normal request: this is used to ask for permissions relative to CORS restrictions. OPTIONS请求是一个普通请求:这用于请求相对于CORS限制的权限。 Have a look to this page to understand how CORS work under the hood. 看看这个页面 ,了解CORS如何在幕后工作。

In your case, this is a pure CORS related issue. 在您的情况下,这是一个纯粹的CORS相关问题。 The OPTIONS request contains this header: 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". 这意味着:您只能使用这些标题:“授权”,“内容类型”,“接受”和“X-Mashape-Authorization”。

As you can see, " cache-control " and " x-requested-with " are not listed in 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-origin: “*”
  • Access-Control-Allow-Methods :"GET, PUT, POST , DELETE, OPTIONS" Access-Control-Allow-Methods:“GET,PUT, POST ,DELETE,OPTIONS”
  • Access-Control-Allow-Headers :" Authorization , Content-Type, Accept, X-Mashape-Authorization" Access-Control-Allow-Headers:“ 授权 ,内容类型,接受,X-Mashape-Authorization”

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. 在这里,我们可以看到我们提示访问“authorization”标头,并且服务器正在接受此标头,使用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-origin:“*”
  • Access-Control-Allow-Methods :"GET, PUT, POST, DELETE, OPTIONS" Access-Control-Allow-Methods:“GET,PUT,POST,DELETE,OPTIONS”
  • Access-Control-Allow-Headers :"Authorization, Content-Type, Accept, X-Mashape-Authorization" Access-Control-Allow-Headers:“授权,内容类型,接受,X-Mashape-Authorization”

Here, the "Access-Control-Request-Headers" header prompt access for "cache-control", which the server does not provide, so the CORS requirements are not satisfied and 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/ . 这是一个JSFiddle引用您的问题的不同工作和不工作演示: 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. 注意细节以了解正在发生的事情,几乎没有评论,但他们在这里强调代码中最棘手的部分。

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. 作为奖励,我已经向DropZone的GitHub存储库发送了拉取请求来修复此问题( https://github.com/enyo/dropzone/pull/685 ),它允许您通过DropZone删除预定义的标头。 Give it a try: 试试看:

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
    }
});

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. 我在example.com上的JavaScript可以访问example.com上的任何内容,但不允许从demonst.com,example.net或api.example.com读取任何内容。 They're from a different origin. 他们来自不同的起源。 Here's a table of what counts as the same origin . 这是一个统计相同来源的表格

Without it, I could write a web page that steals all your gmail and private Facebook photos. 没有它,我可以写一个网页,窃取你所有的Gmail和私人Facebook照片。 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. 我的恶意JavaScript会向gmail.com和facebook.com发出网络请求,查找指向您的电子邮件和照片的链接,加载这些数据,然后将其发送到我自己的服务器。

But some services, like APIs, are designed to be accessed by other services. 但是某些服务(如API)旨在由其他服务访问。 That's where CORS comes in - Cross-Origin Resource Sharing. 这就是CORS的用武之地 - 跨源资源共享。 Web services can use CORS to tell browsers that it's fine to allow access from scripts. Web服务可以使用CORS告诉浏览器允许从脚本访问是完美的。 If you want to test your code by submitting to your own server, make sure your server is sending the required HTTP response headers . 如果要通过提交到自己的服务器来测试代码,请确保您的服务器正在发送所需的HTTP响应标头

If you're developing locally, you must also be sure to test from a web server - an address beginning with http:// , not file:// . 如果您在本地进行开发,则还必须确保从Web服务器进行测试 - 以http://开头的地址,而不是file:// The protocol is part of the origin, so you can't submit to an http endpoint from a file URL. 该协议是源的一部分,因此您无法从文件URL提交到http端点。


CORS has different types of requests. CORS有不同类型的请求。 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?" 这意味着浏览器将向服务器发送一条请求,说“CORS的请求是否正常?” using the HTTP OPTIONS method before sending the actual request. 在发送实际请求之前使用HTTP OPTIONS方法。 Any request with custom headers requires preflighting; 任何带有自定义标题的请求都需要预检; that's where your HTTP OPTIONS is coming from. 就是你的HTTP OPTIONS的来源。 jQuery adds a custom X-Requested-With header to AJAX requests , so even if you hadn't added those you'd still see that Options request before the actual POST. jQuery 为AJAX请求添加了一个自定义的X-Requested-With标头 ,所以即使你没有添加那些,你仍然会在实际POST之前看到Options请求。

From your screenshots, it looks like Imgur is going to allow your HTTP POST method. 从截图中看,Imgur似乎将允许您的HTTP POST方法。 Let's move on to figuring out why that's not working. 让我们继续弄清楚为什么那不起作用。


We're using the Imgur image upload API endpoint . 我们正在使用Imgur图片上传API端点 This has one required parameter ( image ), and if we only want anonymous uploads all we need is a registered app . 这有一个必需参数( image ),如果我们只想匿名上传,我们需要的只是一个注册的应用程序 The upload method lets us send a simple URL to an image for upload, so let's try making an AJAX request to Imgur: 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 API to read the file from the form, and send that. 下一步是尝试使用Filereader API从表单中读取文件,然后发送。 Here's a CoffeeScript submit handler for that: 这是一个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 Dropzone to 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 success callback gets two arguments: the file that was uploaded, and the response from the server. Dropzone success回调有两个参数:上传的文件和服务器的响应。 You'll probably be most interested in the latter; 你可能对后者最感兴趣; Imgur sends back an id and a link parameter on success that you can use to show the user their newly-uploaded image. Imgur会在成功时发回一个id和一个link参数 ,您可以使用该参数向用户显示他们新上传的图像。


There's an example project for using the Imgur API from JavaScript available on Github here . 这里有一个示例项目, 可以在Github上使用JavaScript 提供的Imgur API。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM