浏览器同源策略
源是指协议、主机名、端口共同组成的部分
https://www.baidu.com
- https 协议
- www.baidu.com 主机名(域名)
- 端口默认443
如果两个url的源相同,我们就称之为同源,否则称为不同源
当一个源去访问另一个源资源时,就会产生跨源,同源策略就是用来限制一些跨源访问的,比如ajax请求,cookie访问等等
解决跨域方案
跨域资源共享(cors)
cors是浏览器为ajax请求设置的一种跨域请求机制,让其在服务器允许的情况下进行跨域访问,主要通过响应头来告诉浏览器服务器是否允许进行跨域访问
跨域资源共享将请求分为两类:简单请求跟非简单请求
简单请求需满足以下条件
- 请求方法为get,post,head
- 请求头只能包含以下字段
1. Accept(浏览器能够接受的响应内容类型)
2. Accept-Language(浏览器能够接受的自然语言列表)
3. Content-Type (请求对应的类型,只限于 text/plain、multipart/form-data、application/x-www-form-urlencoded)
4. Content-Language(浏览器希望采用的自然语言)
5. Save-Data(浏览器是否希望减少数据传输量)
不满足上面任何一条即为非简单请求
对于简单请求,处理流程如下
- 浏览器发出简单请求时,会在请求头加Origin字段,表示当前请求的源信息
- 服务器收到请求后,会根据请求头Origin字段来返回相应的内容
- 浏览器接收到响应报文后会根据响应头字段Accept-Control-Allow-Origin来判断,这个字段表示服务器允许跨域请求的源,其中通配符*表示允许任何跨域请求,如果响应头不包含Accept-Control-Allow-Origin或者Accept-Control-Allow-Origin不包含当前源,会抛出错误
处理非简单请求时,浏览器会先发一个预检请求(preflight),预检请求方式为option,会在请求头加Accept-Control-Request-Method字段,值为跨域请求使用的请求方法,在服务端收到预检请求后,除了在响应头部添加 Access-Control-Allow-Origin 字段之外,至少还会添加 Access-Control-Allow-Methods 字段来告诉浏览器服务端允许的请求方法,并返回 204 状态码。浏览器得到预检请求响应的头部字段之后,会判断当前请求服务端是否在服务端许可范围之内,如果在则继续发送跨域请求,反之则直接报错。
jsonp
依赖的是script标签跨域引用js文件不会受到同源策略的限制
过程
- 声明一个全局的函数fn,用来处理返回值
- 将请求地址赋值给变量url
- 创建script标签,将url赋值给script的src属性
- 服务器接收的请求后,做出相应的逻辑处理,将结果已回调函数的形式返回给浏览器
问题
- 只能发送get请求,对于请求方式以及参数有限制
- 一旦开始无法停止
- 无法捕获异常
Websocket
webSocket是html5规范提出的双工通信协议,适用于服务器以及浏览器进行实时通信
var ws = new WebSocket("ws://aaa.com");
ws.onopen = function(){
// ws.send(...);
}
ws.onmessage = function(e){
// console.log(e.data);
}
代理转发
跨域是为了突破浏览器的同源策略限制,既然同源策略只存在于浏览器,那可以换个思路,在服务端进行跨域,比如设置代理转发。这种在服务端设置的代理称为
反向代理
,对于用户而言是无感知的
下面的例子是 webpack-dev-server 配置代理的示例代码。当浏览器发起前缀为 /api 的请求时都会被转发到 http://localhost:3000 这个网址,然后将响应结果返回给浏览器。对于浏览器而言还是请求当前网站,但实际上已经被服务端转发。
// webpack.config.js
module.exports = {
//...
devServer: {
proxy: {
'/api': 'http://localhost:3000'
}
}
};