什么是跨域?
跨域,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器施加的安全限制。
说到这里,大家肯定会好奇,那么什么是同源策略呢?
所谓同源就是指:域名,协议,端口均相同
http://www.123.com/index.html 调用 http://www.123.com/server.js(非跨域)
http://www.123.com/index.html 调用 http://www.456.com/server.js(域名不同,所以跨域)
http://abc.123.com/index.html 调用 http://def.123.com/server.js(子域名不同,所以也是跨域)
http://www.123.com:8080/index.html 调用 http://www.123.com:8081/server.js(端口不同,所以也是跨域)
http://www.123.com/index.html 调用 https://www.123.com/server.js(因为协议不同,所以也跨域了)
注意:localhost 和 127.0.0.1 虽然都指向本机,但是也是属于跨域
跨域的三种解决方案
- JSONP
由于同源策略只对 js 代码进行限制,所以,我们可以通过其他的方式来绕过同源策略的限制,从而来发送请求。
最后发现浏览器只对 ajax 请求有同源请求限制,而对 script 标签 src 属性、link 标签 href 属性和 img 标签 src 属性没有这种限制。因此就有了一种解决跨域的方法,以下介绍了两种方式中的 jsonp 来解决跨域:
1. 使用原生 js 来书写 JSONP解决跨域问题
这里主要是创建了一个 script 标签,并且设置它的 src 属性为我们所要请求的服务器地址,然后将这个 scritp 标签添加到页面中,这样就完成了一次请求的发送。值得提出的是:在服务器端返回的数据要以 js 代码的形式返回。
let script = document.createElement('script');
script.setAttribute('src','http://127.0.0.1:3000');
document.getElementsByTagName('head')[0].appendChild(script);
document.getElementsByTagName('head')[0].removeChild(script);
注意:上面的最后一行代码,是因为你发送了一次请求它就会添加一条 script 标签,在实际项目中,请求的次数肯定不止一次,所以如果不删除,就会有很多条 scritp 标签,导致代码冗余。
2. jQuery 中使用JSONP来解决跨域
主要思路:在请求地址后面添加一个 ?callback=?,将 ajax 方法中的 dataType 设置为 jsonp,最后服务器会接收一个由 jquery自动生成 callback 函数,将要返回的数据放在这个函数中。
$.ajax({
url : 'http://127.0.0.1:3000/stu?callback=?',
dataType:'jsonp',
success : function(data){
console.log(data);
}
})
- CORS
CORS 方法可以说是解决 ajax 跨域方案中最为优雅的,最为简单的方法
实际上,跨域的请求会正常发送到服务器,服务器也会正常接收到请求并且也会正常的返回响应,那为什么还会出现跨域呢?那就是因为浏览器的同源策略,导致浏览器不会将返回的数据交给 js 来执行。
// 创建一个中间件,这个中间件的作用是允许跨域
const allowCorssDomain = function(req,res,next){
// 我们在这个中间件里面主要是设置响应头
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With,Origin,Content-Type,Accept");
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
res.header('Access-Control-Allow-Credentials','true');
next();
}
app.use(allowCorssDomain);
CORS 方法其实很简单,只需要在响应头里面添加一些键值对即可,如以上代码
- 搭建代理服务器
总的来说导致跨域的问题就是因为浏览器的安全策略的限制,但是如果是服务器向服务器发送请求,就不会有这样的安全限制了
所以,就有了代理服务器这么一说,可以先让 ajax 请求同源的代理服务器,再由代理服务器向目标服务器发送请求,这样就圆满的解决了跨域的问题
具体操作如下:
首先我们需要再创建一个服务器。
代理服务器可以使用express proxy-server
来创建的。
接下来需要对代理服务器进行一个配置,需要安装一个中间件
npm i http-proxy-middleware
具体配置如下:
// 对中间件进行一个配置
const options = {
target : 'http://127.0.0.1:3000', // 目标服务器的地址
changeOrigin : true , // 是否可以改写 url
pathRewrite : {
// 定义你的改写规则
'^/api' : '/'
}
}
接下来对这个中间件进行注册
// url 以api开头的,要用 proxy 这个中间来进行处理
app.use('/api',proxy.createProxyMiddleware(options));
最后,在客户端发送请求的时候,就要在前面添加 api ,如下:
$.ajax({
url : '/api/stu', // 添加 api 这个前缀,代表该请求要转发
type : 'get',
success : function(data){
console.log(data);
}
})