浏览器为什么要阻止跨域请求?如何解决跨域?每次跨域请求都需要到达服务端吗?
为什么存在跨域?
为了安全采用浏览器同源策略的限制, 防止csrf攻击。无法共享不同域名的资源,同时也限制了DOM的读取
- 协议
- 域名
- 端口
同源策略又分为以下两种
- DOM同源策略:禁止对不同源页面DOM进行操作。这里主要场景是iframe跨域的情况,不同域名的iframe是限制互相访问的。
2. XmlHttpRequest同源策略:禁止使用XHR对象向不同源的服务器地址发起HTTP请求。(J基本的。发起的每一次HTTP请求都会带上请求地址对应的cookie.)
解决方案:
服务器代理, 如nginx
跨域资源共享 CORS
CORS, Cross-origin resource sharing
- 简单请求。HEAD、GET、POST请求方法且请求头相对简单。
客户端
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
服务端
Access-Control-Allow-Origin: http://api.bob.com 必填字段
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
- 复杂请求。PUT、DELETE请求方法, 或者Content-Type: application/json。
不同在于, 通信前, 先进行预请求。
客户端
var xhr = new XMLHttpRequest();
xhr.open('PUT', 'http://api.alice.com/cors', true);
xhr.setRequestHeader('X-Custom-Header', 'value'); // 添加自定义头信息
请求头部
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
服务端
Access-Control-Allow-Methods: GET, POST, PUT 必填字段
Access-Control-Allow-Headers: X-Custom-Header 必填字段
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 1728000
JSONP
基本原理就是通过动态创建script标签,然后利用src属性进行跨域。
限制: 仅支持get请求
var script = document.createElement('script');
script.src = 'demo.js?callback=fun';
document.getElementsByTagName('body')[0].appendChild(script);
document.domain跨子域
适用于:主域名相同,子域名不同。
location.hash
跨域修改父框架src的hash值
限制: 传递数据字节有限