https://segmentfault.com/a/1190000011145364
https://www.zhihu.com/topic/19612046/top-answers
协议+端口号+域名要相同
一个域下的 js 脚本在未经允许的情况下,不能够访问另一个域的内容。这里的同源的指的是两个域的协议、域名、端口号必须相同,否则则不属于同一个域。
- Cookie、LocalStorage 和 IndexDB 无法读取
- DOM 和 Js对象无法获得
- AJAX 请求不能发送
域和子域不同源,但可以设置domain达到同源
crossorigin="anonymous" 的作用是引入跨域脚本
在 HTML5 中有一种方式可以获取到跨域脚本的错误信息,首先跨域脚本的服务器必须通过 Access-Controll-Allow-Origin 头信息允许当前域名可以获取错误信息,然后是当前域名的 script 标签也必须声明支持跨域,也就是 crossorigin 属性。
link、img 等标签均支持跨域脚本
XHRAPI调用相同,不过浏览器会处理请求
请求:
GET /resource.js HTTP/1.1
Host: third.com
Origin: http://example.com
...
响应:
HTTP/1.1 200 OK
Access-Control-Allow-Origin:http://example.com
...
third.com 同意 example.com的请求,就会返回Access-Control-Allow-Origin,否则不返回对应信息。
Access-Control-Allow-Origin:* 允许来自任何源的请求。
CORS请求会省略cookie和HTTP认证等用户凭据:
Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie也无法读取服务器域名下的Cookie。
要启用cookie和HTTP认证:
-
客户端需要XHR请求时额外发送withCredentials属性。
-
同时,服务器以适当的首部(Access-Control-Allow-Credentials)响应。不能设为星号,必须指定明确的、与请求网页一致的域名。
-
cookie设置 domain+path 根域名
(Cross-Origin Resource Sharing) 跨域资源共享
http://www.ruanyifeng.com/blog/2016/04/cors.html
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。
浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
XHR允许设置自定义HTTP首部,但有些首部是应用代码不能设定的:
Accept-Charset, Accept-Encoding,Access-Control-*
Host, Upgrade, Connection, Reffer, Origin
Cookie, Sec-*, Proxy-*以及其他很多首部
只要同时满足以下两大条件,就属于简单请求。
- method:
GET, HEAD, POST
- HTTP的头信息不超出以下几种字段:
Content-Type:application/x-www-form-urlencoded , multipart/form-data , text/plain
Accept
Accept-Language
Content-Language
Last-Event-ID
- 对于简单请求,浏览器自动加origin请求头
//js
Origin: http://api.bob.com
//server
Access-Control-Allow-Origin: * //或者值http://api.bob.com
Access-Control-Allow-Methods:'GET'
Access-Control-Allow-Credentials: true // cookie
Access-Control-Expose-Headers: FooBar // 暴露的返回头
Content-Type: text/html; charset=utf-8- 发送cookie
CORS请求默认不发送Cookie和HTTP认证信息
//服务器配置:
Access-Control-Allow-Credentials: true
//js:
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;method:不是简单请求中的一种
Content-Type:不是简单请求中的一种
浏览器�先发送option, Preflighted requests请求
服务器收到"预检"请求以后,检查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段以后,确认允许跨源请求,就可以做出回应。
//请求:js
OPTIONS
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Origin: http://localhost:8080
//响应:server
Access-Control-Allow-Origin: http://localhost:8080
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Content-Type: text/html客户端被限制只能发送“简单的跨源请求”,包括只能使用特定的方法(GET POST HEAD)。只能访问可以通过XHR发送并读取的HTTP首部
如果客户端需要写或者读自定义的HTTP首部,想要使用“不简单的方式”发送请求,那么它必须首先要获得第三方服务器的许可,发送一个preflight请求(options)
//preflight请求
OPTIONS /resource.js HTTP1.1
Host: third.com
Origin: http://example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: My-Customer-Header
//响应
//HTTP1.1 200 OK
Access-Control-Allow-Origin: http://example.com
Access-Control-Allow-Methods: GET,POST,PUT
Access-Control-Allow-Headers: My-Customer-Header
//正式的CORS请求
https://segmentfault.com/a/1190000007665361#articleHeader1
JSONP只支持GET请求
js 文件不受浏览器同源策略的影响,所以通过 Script 便签可以进行跨域的请求
- 前端
前端发送给后端一个方法名字。后端在数据包将返回数据包装为方法参数,与方法,一起返回。�前端拿到返回�结果后,会执行该函数。
function jsonp(url, jsonpCallback, success) {
let script = document.createElement("script");
script.src = url;
script.async = true;
script.type = "text/javascript";
window[jsonpCallback] = function(data) {
success && success(data);
};
document.body.appendChild(script);
}
jsonp(
"http://xxx",
"callback",
function(value) {
console.log(value);
}
);- 后端
解析请求的js资源ulr,并做处理返回。返回带着前端需要回调的函数名
//返回content
onBack({"status": true, "user": "admin"})- 缺点
它支持 GET 请求而不支持 POST 等其它类行的 HTTP 请求。
它只支持跨域 HTTP 请求这种情况,不能解决不同域的两个页面或 iframe 之间进行数据通信的问题
server{
# 监听9099端口
listen 9099;
# 域名是localhost
server_name localhost;
#凡是localhost:9099/api这个样子的,都转发到真正的服务端地址http://localhost:9871
location ^~ /api {
proxy_pass http://localhost:9871;
}
}反向代理
通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。
#proxy服务器
server {
listen 81;
server_name www.domain1.com;
location / {
proxy_pass http://www.domain2.com:8080; #反向代理
proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名
index index.html index.htm;
# 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用
add_header Access-Control-Allow-Origin http://www.domain1.com; #当前端只跨域不带cookie时,可为*
add_header Access-Control-Allow-Credentials true;
}
}实现主域名下的不同子域名的跨域操作,我们可以使用设置 document.domain
只能用于二级域名相同的情况下,比如 a.test.com 和 b.test.com 适用于该方式。
只需要给页面添加 document.domain = 'test.com' 表示二级域名都相同就可以实现跨域
WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,是server push技术的一种很好的实现。
原生WebSocket API使用起来不太方便,我们使用Socket.io,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。
a.) 页面和其打开的新窗口的数据传递 b.) 多窗口之间消息传递 c.) 页面与嵌套的iframe消息传递 d.) 上面三个场景的跨域数据传递