我尝试使用jQuery Dropzone将图像上传到Imgur或任何其他域,但这不起作用。
这是我的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 *************"
这不起作用。它表示返回码为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.
哪个可以翻译
多源请求被阻止:策略“Same origin”不允许查看https://api.imgur.com/3/upload中的远程资源。这可以通过在samin域上移动资源或启用CORS来修复。
答案 0 :(得分:16)
OPTIONS请求是一个普通请求:这用于询问与CORS限制相关的权限。请查看this page以了解CORS如何在幕后工作。
在您的情况下,这是一个纯粹的CORS相关问题。 OPTIONS请求包含此标头:
Access-Control-Request-Headers: authorization,cache-control,x-requested-with
这意味着:我可以使用" 授权"," 缓存控制"和" x-requested-with "我的跨域AJAX请求中的标头?
您得到的答案如下:
Access-Control-Allow-Headers :"Authorization, Content-Type, Accept, X-Mashape-Authorization"
这意味着:您只能使用这些标题:"授权","内容类型","接受"和&# 34 X-Mashape-授权"
如您所见," 缓存控制"和" x-requested-with "在允许列表中未列出,导致浏览器拒绝该请求。
我来到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');
xhr.send(data);
以下是运行此代码时发送的预检请求标头(如Firefox 30 devtools所示,并且我已删除不相关的标头,例如User-Agent,Accept ...):
以及相应的响应标题
在这里,我们可以看到我们提示访问"授权" header,并且服务器正在接受此标头,使用POST方法和任何原始URL,因此满足CORS要求并且浏览器允许该请求。
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中的相同):
此处,"访问控制请求标头"标题提示访问" cache-control",服务器未提供,因此CORS要求不满意,请求被浏览器拒绝。
这是一个JSFiddle,引用了针对您的问题的不同工作和不工作的演示:http://jsfiddle.net/pomeh/Lfajnebh/。注意细节以了解发生了什么,几乎没有评论,但他们在这里强调代码中最棘手的部分。
作为奖励,我已经向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
}
});
答案 1 :(得分:2)
您正在使用浏览器same-origin security policy。每个浏览器都有一个; "来源"基本上意味着"同一个网站"。我在example.com上的JavaScript可以在example.com上访问它喜欢的任何内容,但它不允许从demonst.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。
如果您要在本地开发,还必须确保从网络服务器进行测试 - 以http://
开头的地址,而不是file://
。该协议是原始协议的一部分,因此您无法从文件URL提交到http端点。
CORS有不同类型的请求。某些请求被视为简单请求,但其他请求 - 具有自定义标头的请求 - 需要" preflighting"。这意味着浏览器将向服务器发送一个请求,说'&34;这个请求对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。上传方法允许我们向图片发送简单的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的示例项目。