同源策略
说到跨域,我们不得不说说同源策略,因为造成前端跨域问题的“罪魁祸首”就是浏览器的同源策略
那么什么是同源呢?
按照浏览器同源策略,不同的源是不能进行请求操作的;
两个页面只要满足相同的协议,域名,端口,就表示两个页面之间有相同的源,这里就不举例子说明了
知道了什么是同源策略,因为不同源造成的请求错误,发送的请求会跨域,在开发中经常遇到
怎么解决跨域?
解决跨域问题是开发者必备的技能,不管在开发环境还是生产环境,跨域都会经常遇到
这里主要介绍三种常见的解决方法,JSONP,CORS(跨域资源共享)以及反向代理
1、JSONP(JSON with Padding)
首先要说明的是JSONP只支持get请求,支持老式浏览器
具体怎么实现的?
我们都知道script标签可以引入不同源的js文件,而且引入的js会立即执行
demo.htm
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script src='http:www.jsthin.com/js/demo.js'></script> </body> </html>
demo.js
console.log('我是src请求的文件,我马上被执行了')
这时浏览器控制台会打印出‘我是src请求的文件,我马上被执行了’,再来看看下面的代码
demo.html
<body> <script> function printf(data) { console.log(data) } </script> <script src='http:www.jsthin.com/js/demo.js'></script> </body>
demo.js
printf('我是jsonp请求回来的js文件,我被执行了')
我们也可以看到浏览器控制台输出了‘我是jsonp请求回来的js文件,我被执行了’,JSONP就是使用这样的原理实现的跨域请求,将数据data通过函数参数的方式传递
接下来我们看一个完整的JSONP应用
<body> <button onclick=sendRequest"('printf')">JSONP跨域请求</button> <script> function printf(data) { let jsonpScript = document.getElementsByClassName('jsonpScript')[0]; document.body.removeChild(jsonpScript); } function sendRequest(callback) { let jsonpScript = document.createElement('script'); jsonpScript.src = `http://www.jsthin.com/js/demo.js?callback=${callback}`; jsonpScript.className = 'jsonpScript'; document.body.appendChild(jsonpScript); } </script> </body>
printf({ name: 'jsthin', age: 20 })
2.、CORS(Cross-origin resource sharing)
普通请求跨域:后端设置Cross-origin resource sharing即可,前端不需要设置,若需要带cookie,前后端都需要设置
这里说明一下前端的设置
-
- 原生ajax
// 前端设置是否带cookie xhr.withCredentials = true;
- jQuery的ajax
$.ajax({ ... xhrFields: { withCredentials: true // 前端设置是否带cookie }, crossDomain: true, // 会让请求头中包含跨域的额外信息,但不会含cookie ... });
- axios
axios.defaults.withCredentials = true
- vue-resource
Vue.http.options.credentials = true
- 原生ajax
3、nginx代理跨域
server{ # 监听8080端口 listen 8080; # 域名是localhost server_name localhost; #凡是localhost:8080/api这个样子的,都转发到真正的服务端地址http://www.b.com:8080 location ^~ /api { proxy_pass http://www.b.com:8080; } }