老生长谈的问题,社区有很多总结的非常完善的好文。笔者在这记录一下自己的见解,有时间了再补充细节。
跨域原因
同源策略:协议、域名、端口号必须一致。
同源策略限制了三个方面:
1.dom层面:不同站点之间不能相互访问和操作dom
2.数据层面:不能获取不同源站点的cookie,LocalStorage、indexDB等数据
3.网络层面:不能通过XMLHttpRequest向不同源站发送请求
但是link、img、script标签都没有跨域限制
跨域分类
dom层面
1.片段标识符url中的hash
2.window.name
3.postMessage
4.document.domain
document.domain + iframe 适用于主域名相同,子域名不相同
window.name + iframe 利用name值最长可以2M,并用不同页面或不同域名加载后依然存在的特性
location.hash + iframe 适用于通过C页面来实现与B页面通信的场景
以上三种都用不到
postMessage
html5新增的api
页面和新打开的窗口间数据传递
多窗口之间数据传递
页面与嵌套的iframe之间的数据传递
上面三个场景之间的跨域传递
postmessage接收两个参数
参数一:发送的数据
参数二:你要发送给谁就写谁的地址(协议+域名+端口),也可以设置为*,表示任意窗口,设置为/表示与当前窗口同源的窗口
网络层面
1.jsonp
2.cors
3.服务器代理
4.websocket
5.node中间件代理
jsonp
原理是通过添加一个script标签,向服务器请求jsonp数据,这样就不受同源政策限制。服务器收到请求后,将数据放在一个callback回调函数中传过来,比如axios
不过只支持get请求,且不安全。可能遇到xss攻击,不过它的好处时可以向老浏览器或不支持cors的网站请求数据
jsonp格式
[见笔者另一篇文章,写的很详细](https://juejin.cn/post/7000618779826716703)
cors
cors分为简单请求和复杂请求
另外cors请求默认不包含cookie以及http认证信息,如果需要包含cookie,需要满足几个条件
服务器指定了 Access-Control-Allow-Credentials:true
开发者须在请求中打开withGredentials属性:xhr.withCredentials = true
Access-Control-Allow-Origin不要设置为星号,指定明确的与请求网页一致的域名,这样就不会把其他域名的cookie上传。
简单请求:同时满足两个条件
1.请求方法是head,get,post
2.请求头信息不超过以下几个字段
Accept、Accept-Language、Content-Language、Last-Event-Id、Content-Type值为三者之一application/x-www/form/urlencoded、multipart/form-data、text/plain
浏览器直接发出cors请求,具体来说就是在头信息中增加origin字段,表示请求来源来自那个域(协议+域名+端口)服务器根据这个值决定是否同意请求。如果同意,返回的响应会多出以下响应头信息。
Access-Control-Allow-Origin 和Origin一致,这个字段必须
Access-Control-Allow-Credentials: true 表示是否允许发送cookie 这个字段可选
Access-Control-Expose-Headers: FooBar 指定返回其他字段的值 这个字段可选
Content-Type: text/html ;charset=utf-8 表示文档类型
非简单请求,比如put或delete请求,或Content-Type为application/json,就是非简单请求
非简单cors请求,正是请求前会发送一次options类型的查询请求,称为预检请求,询问服务器是否支持网页所在域名的请求,以及可以使用哪些头信息字段。只有收到肯定的答复、才会发起正式XMLHttpRequest请求,否则报错
预检请求的方法是options,它的头信息中有几个字段
origin 表示来自哪个域,这个字段是必须的
Access-Control-Request-Method 列出cors请求会用到哪些http方法,这个字段是必须的
Access-Control-Request-Headers 指定cors请求会额外发送的头信息字段,用逗号隔开
options请求次数过多也会损耗性能,所以要尽量减少options请求,可以让服务器在请求返回头部添加
Access-Control-Max-Age: Number 数字,单位是秒
表示预检请求的返回结果可以被缓存多久,在这个时间范围内在请求就不需要预检了。不过这个缓存只对完全一样的url才会生效。
服务器代理Nginx
Node中间件代理;proxy
websocket
html5新增的通信协议,以ws或wss为协议前缀。
记录记录!