一,什么是跨域?
1.跨域:浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器施加的安全限制
2.同源:域名,协议,端口号都相同。比如:
http://www.123.com/index.html 调用 http://www.123.com/server.php (非跨域) http://www.123.com/index.html 调用 http://www.456.com/server.php (主域名不同:123/456,跨域) http://www.123.com:8080/index.html 调用 http://www.123.com:8081/server.php http://www.123.com/index.html 调用 https://www.123.com/server.php (协议不同:http/https,跨域)
浏览器执行javascript脚本时,会检查这个脚本属于哪个页面,如果不是同源页面,就不会被执行。
请注意:localhost和127.0.0.1虽然都指向本机,但也属于跨域。
二,解决办法
1.JSONP:
1.1JSONP原理:
在js中,我们直接用XMLHttpRequest请求不同域上的数据时,是不可以的。但是,在页面上引入不同域上的js脚本文件却是可以的,jsonp正是利用这个特性来实现的。
代码:
<script type="text/javascript"> function dosomething(jsondata){ //处理获得的json数据 } </script> <script src="http://example.com/data.php?callback=dosomething"></script>
2.代理:HttpClient
例如www.123.com/index.html需要调用www.456.com/server.php,可以写一个接口www.123.com/server.php,由这个接口在后端去调用www.456.com/server.php并拿到返回值,然后再返回给index.html,这就是一个代理的模式。相当于绕过了浏览器端,自然就不存在跨域问题。
3.CORS :Cross-Origin Resource Sharing(跨域资源共享)
是一种允许当前域(origin)的资源(比如html/js/web service)被其他域(origin)的脚本请求访问的机制。
3.1,原理:
当使用 XMLHttpRequest 发送请求时,浏览器如果发现违反了同源策略就会自动加上一个请求头 origin,后端在接受到请求后确定响应后会在 Response Headers 中加入一个属性 Access-Control-Allow-Origin,值就是发起请求的源地址(http://127.0.0.1:8888),浏览器得到响应会进行判断 Access-Control-Allow-Origin 的值是否和当前的地址相同,只有匹配成功后才进行响应处理。
前端代码:
// http://127.0.0.1:8888/cors.html var xhr = new XMLHttpRequest(); xhr.onload = function(data) { var _data = JSON.parse(data.target.responseText) for(key in _data) { console.log('key: ' + key + ' value: ' + _data[key]); } }; xhr.open('POST','http://127.0.0.1:2333/cors',true); xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); xhr.send();
后端代码:
/ http://127.0.0.1:2333/cors app.post('/cors', (req, res) => { if(req.headers.origin) { res.writeHead(200, { "Content-Type": "text/html; charset=UTF-8", "Access-Control-Allow-Origin": 'http://127.0.0.1:8888' }); let people = { type: 'cors', name: 'weapon-x' } res.end(JSON.stringify(people)); } })
4.服务器跨域
在前后端分离的项目中可以借助服务器实现跨域,具体做法是:前端向本地服务器发送请求,本地服务器代替前端再向真实服务器接口发送请求进行服务器间通信,本地服务器其实充当个「中转站」的角色,再将响应的数据返回给前端。
前端代码:
/ http://127.0.0.1:8888/server var xhr = new XMLHttpRequest(); xhr.onload = function(data) { var _data = JSON.parse(data.target.responseText) for(key in _data) { console.log('key: ' + key +' value: ' + _data[key]); } }; // 向本地服务器发送请求 xhr.open('POST','http://127.0.0.1:8888/feXhr',true); xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); // 以参数形式告知需要请求的后端接口 xhr.send("url=http://127.0.0.1:2333/beXhr");
后端代码:
// http://127.0.0.1:8888/feXhr app.post('/feXhr', (req, res) => { let url = req.body.url; //使用 superagent 向实际接口发起请求 superagent.get(url).end((err, docs) => { if(err) { console.log(err); return } // 返回给前端 res.end(docs.res.text); }) }) // http://127.0.0.1:2333/beXhr app.get('/beXhr', (req, res) => { let obj = { type: 'superagent', name: 'weapon-x' }; res.writeHead(200, {"Content-Type": "text/javascript"}); //响应 res.end(JSON.stringify(obj)); })