看一下就懂的 跨域

438 阅读2分钟

为啥要跨域?

那必须得从同源策略说起了

什么是同源

  • window.originlocation.origin可以得到当前
  • 源=协议+域名+端口号
  • 如果两个url的协议 域名 端口号
  • 完全一致,那么这两个url就是同源
  • 举例

同源策略定义

  • 不同源的页面之间,不准互相访问数据
  • 浏览器规定:如果js运行在A里,那么就只能获取A的数据
  • 不能获取源B的数据,即不允许跨域
  • 这就是浏览器故意设计的功能,就是为了保护用户隐私而设计的
  • 举例

如何解决同源策略的限制呢

方法一:CORS

  1. CORS 是跨域资源共享的缩写
  2. 该技术通过在目标域名返回 CORS 响应头来达到获取该域名的数据的目的
  3. 改技术核心就是设置 response header,分为简单请求和复杂请求两种
  4. 简单请求只需要设置 Access-Control-Allow-Origin: 目标源 即可,复杂请求则分两步走,第一步是浏览器发起 OPTIONS 请求,第二步才是真实请求。OPTIONS 请求需要把服务器支持的操作通过响应头来表明,如 Access-Control-Allow-Methods: POST, GET, OPTIONS,另外一个重要的响应头是 Access-Control-Allow-Credentials: true 用来表明是否接受请求中的 Cookie。
  5. 优点是通过简单的配置就能跨域
  6. 缺点是某些古老浏览器不支持 CORS 或不支持 Credentials
  7. 解决办法是用 JSONP 或 P3P (这个目前没有研究)等技术
  8. 示例:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>CORS</title>
</head>
<body>
    <script>
	const xhr = new XMLHttpRequest();
	xhr.open('GET', 'http://127.0.0.1:3000', true);
	xhr.onreadystatechange = function() {
	    if(xhr.readyState === 4 && xhr.status === 200) {
	        alert(xhr.responseText);
	    }
	}
	xhr.send(null);
    </script>
</body>
</html>
  • 这似乎跟一次正常的异步 ajax 请求没有什么区别,关键是在服务端收到请求后的处理:
require('http').createServer((req, res) => {

    res.writeHead(200, {
	'Access-Control-Allow-Origin': 'http://localhost:8080'
    });
    res.end('这是你要的数据:1111');

}).listen(3000, '127.0.0.1');

console.log('启动服务,监听 127.0.0.1:3000');
  • 关键是在于设置相应头中的 Access-Control-Allow-Origin,该值要与请求头中 Origin 一致才能生效,否则将跨域失败。

解决方法二:JSONP

  1. JSONP 是 json with padding 的缩写
  2. 该技术通过 script 不受同源策略限制来达到跨域的目的
  3. 该技术核心是前端构造 script 发起 get 请求,后端将数据放到 js 回调里,前端接受响应后执行回调拿到数据
  4. 是通过简单的约定就能跨域
  5. 是不支持 get 以外的动词,而且存在 csrf 风险
  6. 决办法是 CORS 或 csrf token
  7. 代码示例:
  • 后端逻辑
//server.js
const url = require('url');
	
require('http').createServer((req, res) => {

    const data = {
	x: 10
    };
    const callback = url.parse(req.url, true).query.callback;
    res.writeHead(200);
    res.end(`${callback}(${JSON.stringify(data)})`);

}).listen(3000, '127.0.0.1');

console.log('启动服务,监听 127.0.0.1:3000');
  • 通过 node server.js 启动服务,监听端口 3000,这样服务端就建立起来了前端页面:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index.html</title>
</head>
<body>
    <script>
	function jsonpCallback(data) {
	    alert('获得 X 数据:' + data.x);
	}
    </script>
    <script src="http://127.0.0.1:3000?callback=jsonpCallback"></script>
</body>
</html>