Javascript 访问控制如何允许源标题工作?
显然,我完全误解了它的语义。我想到了这样的事情:Javascript 访问控制如何允许源标题工作?,javascript,cross-domain,cors,Javascript,Cross Domain,Cors,显然,我完全误解了它的语义。我想到了这样的事情: 客户端从http://siteA-原点 MyCode.js的响应头包含访问控制允许来源:http://siteB,我认为这意味着MyCode.js可以对站点B进行跨源引用 客户端触发MyCode.js的一些功能,这些功能反过来向http://siteB,这应该没问题,尽管是跨来源请求 嗯,我错了。它根本不是这样工作的。所以,我已经阅读并试图阅读 有一件事是肯定的-我仍然不明白我应该如何使用这个标题 我对站点A和站点B都有完全的控制权。如何使从站点
http://siteA
-原点http://siteB
,我认为这意味着MyCode.js可以对站点B进行跨源引用http://siteB
,这应该没问题,尽管是跨来源请求我不想使用JSONP。
访问控制允许源站
是一个
当站点A尝试从站点B获取内容时,站点B可以发送一个访问控制允许源站
响应标题,告诉浏览器某些源站可以访问此页面的内容。(原点为a。)默认情况下,站点B的页面为;使用Access Control Allow Origin
标题打开一扇门,通过特定的请求来源进行跨来源访问
对于站点B希望站点A访问的每个资源/页面,站点B应为其页面提供响应标题:
Access-Control-Allow-Origin: http://siteA.com
现代浏览器不会完全阻止跨域请求。如果站点A从站点B请求页面,浏览器将实际在网络级别获取请求的页面,并检查响应头是否将站点A列为允许的请求者域。如果站点B未指示允许站点A访问此页面,浏览器将触发XMLHttpRequest
的错误事件,并拒绝请求JavaScript代码的响应数据
非简单请求
在网络层面上发生的事情可能比上面解释的稍微复杂一些。如果请求是,浏览器首先发送一个无数据的“飞行前”选项请求,以验证服务器是否会接受该请求。在以下情况下,请求是非简单的:
- 使用非GET或POST的HTTP动词(例如PUT、DELETE)
- 使用非简单请求头;唯一的简单请求标头是:
接受
接受语言
内容语言
内容类型
(只有当其值为应用程序/x-www-form-urlencoded
、多部分/表单数据
、或文本/普通
时,这才简单)
如果服务器使用与非简单谓词和/或非简单标头匹配的适当响应标头(Access Control Allow headers
用于非简单标头,Access Control Allow Methods
用于非简单谓词)响应选项飞行前,则浏览器发送实际请求
假设站点A想要发送对/somePage
的PUT请求,且非简单内容类型
值为application/json
,浏览器将首先发送飞行前请求:
OPTIONS /somePage HTTP/1.1
Origin: http://siteA.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type
请注意,访问控制请求方法
和访问控制请求头
由浏览器自动添加;您不需要添加它们。此选项预飞行获取成功响应标题:
Access-Control-Allow-Origin: http://siteA.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type
发送实际请求时(飞行前完成后),行为与处理简单请求的方式相同。换句话说,预飞成功的非简单请求被视为与简单请求相同(即,服务器必须再次发送Access Control Allow Origin
,以获得实际响应)
浏览器发送实际请求:
PUT /somePage HTTP/1.1
Origin: http://siteA.com
Content-Type: application/json
{ "myRequestContent": "JSON is so great" }
服务器会发回一个访问控制允许源站
,就像对一个简单请求一样:
Access-Control-Allow-Origin: http://siteA.com
有关非简单请求的更多信息,请参阅。跨源资源共享-CORS
(又称跨域AJAX请求)是大多数web开发人员可能遇到的问题,根据同源策略,浏览器将客户端JavaScript限制在安全沙箱中,通常JS无法直接与来自不同域的远程服务器通信。过去,开发人员创建了许多复杂的方法来实现跨域资源请求,最常用的方法是:
使用Flash/Silverlight或服务器端作为“代理”进行通信
用遥控器李>
带填充()的JSON李>
将远程服务器嵌入iframe中,并通过片段或窗口进行通信。名称,请参阅
这些棘手的方法或多或少都有一些问题,例如,如果开发人员简单地“评估”JSONP,JSONP可能会导致安全漏洞,以及上面的第3条,尽管它可以工作,但两个域应该在彼此之间建立严格的契约,这既不灵活也不优雅(IMHO:)
W3C引入了跨源资源共享(CORS)作为标准解决方案,以提供安全、灵活和推荐的标准方法来解决此问题
机制
从较高的层次上,我们可以简单地认为CORS是来自域a的客户端AJAX调用与域B上托管的页面之间的契约,典型的跨源请求/响应是:
域AJAX请求头
Host DomainB.com
User-Agent Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8,application/json
Accept-Language en-us;
Accept-Encoding gzip, deflate
Keep-Alive 115
Origin http://DomainA.com
Cache-Control private
Content-Type application/json; charset=utf-8
Access-Control-Allow-Origin DomainA.com
Content-Length 87
Proxy-Connection Keep-Alive
Connection Keep-Alive
域B响应头
Host DomainB.com
User-Agent Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8,application/json
Accept-Language en-us;
Accept-Encoding gzip, deflate
Keep-Alive 115
Origin http://DomainA.com
Cache-Control private
Content-Type application/json; charset=utf-8
Access-Control-Allow-Origin DomainA.com
Content-Length 87
Proxy-Connection Keep-Alive
Connection Keep-Alive
我上面标记的蓝色部分是核心事实,“来源”请求头“表示跨来源请求或飞行前请求的来源”,“访问控制允许来源”响应头表示此页面允许来自DomainA的远程请求(如果值为*表示允许来自
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Origin: http://www.website.com");
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
res.header("Access-Control-Allow-Headers","*");
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
$http({
method: 'POST',
url: 'url,
withCredentials: true,
data : {}
}).then(function(response){
// code
}, function (response) {
// code
});
open -a Google\ Chrome --args --disable-web-security --user-data-dir
axios.get(`https://cors-anywhere.herokuapp.com/[YOUR_API_URL]`,{headers: {'Access-Control-Allow-Origin': '*'}})
.then(response => console.log(response:data);
}
$ pip install -U flask-cors
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
@app.route("/")
def helloWorld():
return "Hello, cross-origin-world!"
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
</customHeaders>
</httpProtocol>
Header type Response header
Forbidden header name no
Access-Control-Allow-Origin: *