跨域:
官方解释:跨域是指浏览器不能执行其他网站的脚本。它是有浏览器的同源策略造成的,是浏览器施加的安全限制。
从这里面我们可以提取到第一个点-->“跨域问题是浏览器产生的”
跨域,又称跨域名访问。其中又分为:二级域名跨域、多级 域名跨域、端口号跨域以及协议跨域。
下面说明这几种跨域,假如一网站是 http://www.abc.com,那么该网站访问其他资源的路径可能是以下几种:
1、http://abc.com 二级域名跨域
2、http://www.abc.cn 主域名跨域
3、http://www.def.com 主域名跨域
4、https://www.abc.com 协议跨域
解决跨域的方法:
一、jsonp 跨域
jsonp跨域是利用,在浏览器当中,img标签的src、以及script标签的src、以及link标签的href不受浏览器同源政策的限制。绕过ajax去请求数据。既然如此,我们就可以利用动态的创建script标签的方式,去跨域请求数据了。
这里我使用node做示例,那么我就利用express来建立一个jsonp数据,之后就来请求这个数据即可
app.get('/jsonp', (req, res, next) => {
res.jsonp({
data: 'this is a jsonp data'
})
})
既然jsonp是利用script标签去请求数据,那么我们就需要动态创建script标签
第一步:定义处理函数,用来处理接收到的数据
function getData(res) {
console.log(res)
}
第二步:创建script标签,去请求数据
let jsonp = document.createElement('script')
jsonp.src = 'http://localhost:3000/jsonp?callback=getData'
这里jsonp默认使用callback作为请求参数
在这之后数据会被打印出来。
jsonp的优势:兼容性比较好(几乎所有浏览器都支持script标签)
jsonp的劣势:jsonp只支持get请求
二、cors跨域
CORS需要浏览器和服务器同时支持,目前几乎所有浏览器都支持CORS,IE不能低于IE10。整个CORS跨域的过程,前端都是浏览器自动完成的,浏览器一旦发现ajax请求跨域资源,就会自动添加一些附加的头信息,有时还会多一次试探性的OPTIONS请求。
CORS又分为简单请求和非简单请求
① 简单请求:
要同时满足以下几个条件:
1、请求方式是 HEAD、GET、POST其中的一个
2、http的请求头不超出以下几种信息:Accept、Accept-Language、Content-Language、Last-Event-ID、Content-Type
3、Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
简单请求时浏览器会自动带上一个请求头" Origin: 客户端域名 ”
当浏览器接收到服务器返回的响应时,会对响应头进行分析。如果 存在 Access-Control-Allow-Origin:“客户端域名”;那么浏览器就会把请求到的数据返回给ajax对象,否则就会触发ajax的onerror事件,抛出一个错误异常
② 非简单请求
对于非简单请求一般分为以下步骤
第一步:
浏览器先发出一个options的请求。并且包含一些头部信息:
Origin:客户端域名Access-Control-Request-Headers: content-type (表明客户端发送的请求头数据)Access-Control-Request-Method: POST (表明客户端发送的请求类型)
第二步:
服务器返回options请求
Access-Control-Allow-Origin:允许跨域的域名(可以是指定域名,也可以是全域名“*”)Access-Control-Allow-Headers: “与客户端对应”Access-Control-Allow-Method: 与客户端的对应或者大于客户端
第三步:
客户端检查options请求的响应头。如
Access-Control-Allow-Origin:允许跨域的域名Access-Control-Allow-Headers: “与客户端对应”Access-Control-Allow-Method: 与客户端的对应或者大于客户端
如果服务器的响应头与浏览器的请求头对应了,浏览器会正式发出请求,服务器对请求做出响应,并带上之前的请求头完成跨域。
不过虽然上面的 对响应头的设置已经可以实现跨域了不过会造成session的丢失,对此我们需要设置另一个请求头参数Access-Control-Allow-Credentials = true,在默认false情况下客户端是不会携带cookies到服务器的。
session丢失的解决:
在响应头里边,指定唯一的允许跨域的域名。服务端在响应头里边。指定Access-Control-Allow-Credentials:true,以及客户端的ajax对象,必须指withCredentials: true;
更好的了解cors跨域的同学可以看看阮一峰老师的《跨域资源共享 CORS 详解》
下面是express实现cors跨域,浏览器端的请求头浏览器会自动添加
router.options('/getCorsData',(req,res)=>{
res.header('Access-Control-Allow-Origin','*') //设置允许访问的域名 * 代表所有
res.header('Access-Control-Allow-Headers','content-type')
res.header('Access-Control-Allow-Method','OPTIONS,POST,PUT')
res.header('Access-Control-Allow-Credentials','true')
res.send(200)
})
三、代理跨域
代理跨域的道理很简单,既然跨域是因为浏览器的同源策略引起的,那么非同源资源不交给浏览器去直接请求,而是让同源服务器去请求再返回给浏览器
express代码示例:
app.get('/getdata', (req, res) => {
request('http://localhost:3000/getCors', (err, response, body) => {
res.json(response)
})
})
以上代码是我是开了两个服务器模拟的一个 3001 端口另一个是3000端口,属于端口跨域,在3001的页面中去访问getdata时服务器向3000端口请求数据,并把数据返回给页面,完成跨域。
但一般我们都是去使用中间件去完成代理跨域。比如 http-proxy-middleware,有兴趣的可以去github中查看使用方法。
总结
知识在于积累,生命在于折腾,有错误的请留言指出,批评使我进步