跨域解决方案

184 阅读2分钟

什么是跨域请求

当请求协议域名端口号任意一个与当前页面不相同的时候,浏览器就会限制请求,不能访问后台数据,这就是浏览器的跨域限制。

首先模拟一下前端跨域请求失败的例子。

前端:

<!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('服务器启动成功');
});

前端浏览器页面会报如下不能跨域请错误:

截屏2022-05-24 下午9.48.09.png

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启动成功');
});