同源策略和跨域问题

283 阅读4分钟

跨域问题是因为什么引起的?是因为浏览器的同源策略

什么是浏览器的同源策略

协议、端口、主机名,完全相同。浏览器不允许使用非同源的数据

image.png 同源策略是指:若页面的源和页面运行过程中加载的源不一致时,出于安全考虑,浏览器会对跨域的资源访问进行一些限制

截屏2024-11-30 下午9.27.09.png 如上图,如果我在百度的站点,通过fetch方法来访问掘金的网页地址的时候,这时候控制台报了错: Access to fetch at 'https://juejin.cn/' from origin 'https://www.baidu.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

这个时候意味着出现了跨域问题。也就是说百度网页跨域访问了掘金,源地址是www.baidu.com/,目标地址是:http…

跨域问题的处理方案

既然是浏览器引起的,那么其实我们只要想办法绕过浏览器访问跨域的url,就不会被拒绝。于是我们可以想到通过代理服务器、nginx等。

proxy代理

对于前端开发而言,大部分的跨域问题,都是通过代理解决的

代理适用的场景是:生产环境不发生跨域,但开发环境发生跨域

原理:

  1. 前端应用将原本需要跨域访问的请求发送给自身的代理服务器
  2. 代理服务器再将请求转发至实际的目标服务器,并从目标服务器获取数据
  3. 最后将数据返回给前端应用。

在实际开发中,只需要对开发服务器增加配置即可

// vue 的开发服务器代理配置,react项目同理
// vue.config.js
module.exports = {
  devServer: { // 配置开发服务器
    proxy: { // 配置代理
      "/api": { // 若请求路径以 /api 开头
        target: "http://dev.taobao.com", // 将其转发到 http://dev.taobao.com
      },
    },
  },
};

CORS

此方案需要后端的配合。

CORS是基于http1.1的一种跨域解决方案,它的全称是Cross-Origin Resource Sharing,跨域资源共享。

它的总体思路是:如果浏览器要跨域访问服务器的资源,需要获得服务器的允许

服务器允许的方式是:当服务器收到请求后,如果允许该请求跨域访问,需要在响应头中添加Access-Control-Allow-Origin字段

该字段的值可以是:

  • *:表示什么人我都允许访问
  • 具体的源:比如http://my.com,表示我就允许你访问

其实针对不同的请求(根据对服务器造成不同程度的影响),CORS 规定了三种不同的交互模式,分别是:

  • 简单请求
  • 需要预检的请求
  • 附带身份凭证的请求

这三种模式从上到下层层递进,请求可以做的事越来越多,要求也越来越严格。

// 后端代码 nodejs 
const allowOrigins = ["http://127.0.0.1:5500", "null"];
module.exports = function (req, res, next) {

  // 1. 处理简单请求
  if ("origin" in req.headers && allowOrigins.includes(req.headers.origin)) {
    res.header("access-control-allow-origin", req.headers.origin);
  }
  
  // 2. 处理预检请求
  // if (req.method === "OPTIONS") {
  //   console.log("这是一个预检请求");
  //   res.header("access-control-allow-origin", req.headers.origin);
  //   res.header(
  //     "Access-Control-Allow-Methods",
  //     req.headers["access-control-request-method"]
  //   );
  //   res.header(
  //     "Access-Control-Allow-Headers",
  //     req.headers["access-control-request-headers"]
  //   );
  // }
  
  // 3. 附带身份凭证的请求
  // res.header("Access-Control-Allow-Credentials", true); // 允许cookie
  
  next();
};

JSONP

JSONP缺点,只能支持GET请求

JSONP的做法是:当需要跨域请求时,不使用AJAX,转而生成一个script元素去请求服务器,由于浏览器并不阻止script元素的请求,这样请求可以到达服务器。服务器拿到请求后,响应一段JS代码,这段代码实际上是一个函数调用,调用的是客户端预先生成好的函数,并把浏览器需要的数据作为参数传递到函数中,从而间接的把数据传递给客户端

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>JSONP Example</title>
  <script>
    // 定义回调函数
    function jsonpCallback(data) {
      console.log('Received data:', data);
      // 处理数据
      document.body.innerHTML += `<p>${data.name}: ${data.message}</p>`;
    }

    // 创建<script>标签并添加到页面中
    function createScript() {
      const script = document.createElement('script');
      script.src = `http://localhost:3000/?callback=jsonpCallback`; // 服务端URL和回调函数名
      document.head.appendChild(script);
    }

    // 页面加载完成后创建<script>标签
    window.onload = createScript;
  </script>
</head>
<body>
  <h1>JSONP Example</h1>
</body>
</html>