什么是跨域请求
当请求协议域名端口号任意一个与当前页面不相同的时候,浏览器就会限制请求,不能访问后台数据,这就是浏览器的跨域限制。
首先模拟一下前端跨域请求失败的例子。
前端:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
fetch('http://localhost:4000/api/data').then((res) => {
console.log('请求成功');
});
</script>
</body>
</html>
后端:
const http = require('http');
const server = http.createServer((req, res) => {
res.end('hello');
});
server.listen('4000', (err, data) => {
console.log('服务器启动成功');
});
前端浏览器页面会报如下不能跨域请错误:
jsonp解决跨域
jsonp的原理主要是利用前端script标签发请求没有跨域限制的特性。jsonp需要前后端的配合完成。
前端代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
function getData(data) {
console.log(data);
}
</script>
<script src="http://localhost:4000/api/data?cb=getData"></script>
</body>
</html>
后端代码:其实前端不用穿入getData,后端也可以直接调用,因为后端的任何返回数据,前端都会当作js执行。
const http = require('http');
const url = require('url');
const server = http.createServer((req, res) => {
const urlobj = url.parse(req.url);
const searchParams = new URLSearchParams(urlobj.search);
console.log(searchParams.get('cb'));
res.end(`${searchParams.get('cb')}("hello")`);
});
server.listen('4000', (err, data) => {
console.log('服务器启动成功');
});
cors解决跨域
cors只需要后端处理,需要设置Access-Control-Allow-Origin响应头。
前端代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
fetch('http://localhost:4000/api/data').then((res) => {
console.log('请求成功');
});
</script>
</body>
</html>
后端代码:
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHeader(200, {
'Access-Control-Allow-Origin': '*',
});
res.end('hello');
});
server.listen('8080', (err, data) => {
console.log('服务器启动成功');
});
http-proxy-middleware解决跨域请求
原理:前端和服务器已经建立了跨域请求,所以前端可以访问代理服务器接口,但是前端和目标服务器并没有建立可跨域设置,所以前端无法直接请求目标服务器接口,需要先将请求转到代理服务器上面,有代理服务器处理之后交给目标服务器对应接口进行处理请求。
前端代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
fetch('http://localhost:8080/api/data').then((res) => {
console.log('请求成功');
});
</script>
</body>
</html>
代理服务器代码:
const http = require('http');
const { createProxyMiddleware } = require('http-proxy-middleware');
const server = http.createServer((req, res) => {
const proxy = createProxyMiddleware('', {
target: 'http://localhost:8082',
changeOrigin: true,
});
res.writeHead(200, { 'Access-Control-Allow-Origin': '*' });
proxy(req, res);
});
server.listen('8080', (err, data) => {
console.log('服务器启动成功');
});
目标请求服务器:
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHeader(200, {});
res.end('hello server2');
});
server.listen('8082', (err, data) => {
console.log('服务器2启动成功');
});