跨域

  • 跨域产生的原因
    当你由一个地址 http://localhost:5500 向另外一个服务器地址 http://127.0.0.1:3000 发送请求的时候,由于 协议名称、域名、端口 中的某一项不一致造成的访问接口失败,就是跨域。
    Access to XMLHttpRequest at ‘http://localhost:3000/users’ from origin ‘http://127.0.0.1:5500’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

  • 浏览器为什么不允许跨域
    1.禁止跨域是浏览器的行为,是浏览器为了网站的安全性,进行从当前的服务,访问其它服务器的地址,浏览器认为这是存在风险的,因此默认会组织跨域。
    2.如果想要成功跨域请求接口,需要后端进行配置,告诉浏览器,我的服务器是安全的,可以进行跨域请求。

跨域的解决方式:后端如何配置

  • 方式一(推荐使用):安装一个包cors,在后端配置这个cors即可,它也是express的中间件;
    安装命令 npm install cors
    后端代码中插入以下代码
 var express = require("express");
  var cors = require("cors");
  var app = express();
  app.use(cors());
  //以下也可以对cors进行手动配置,不进行手动配置也可以
  app.use(
  cors({
    origin: "http://127.0.0.1:5500",
    credentials: true, // 注意:如果允许发送Cookie,origin也就是Access-Control-Allow-Origin这个配置项不允许为*
    allowedHeaders: "Content-Type,Cookie",
  })
);
  • 方式二(了解):自定义响应头配置,实现跨域请求;
// 配置跨域
// router.all("*"): 表示所有前端的请求路由都会经过这个路由。
router.all("*", (req, res, next) => {
  res.header("Access-Control-Allow-Origin", "http://127.0.0.1:5500"); // 设置允许跨域请求的域名,可以设置* "" ["", ""]
  res.header("Access-Control-Allow-Methods", ["GET", "POST", "PUT", "DELETE"]); // 设置跨域的ajax请求能够使用的方法
  res.header("Access-Control-Allow-Headers", "*"); // 设置跨域的ajax请求能够携带的请求头字段
  res.header("Access-Control-Allow-Credentials", true); // 设置允许跨域请求头中携带cookie,默认跨域请求是不允许携带cookie的
  next();
});

  • 方式三(了解,面试常问):jsonp实现跨域请求;掌握jsonp跨域的原理,能够表述出来。很少使用,它只支持GET请求的跨域,POST/PUT/DELETE不支持。
//前端代码
  <script>
    function testFunc(data) {
      console.log("---", data);
    }
  </script>
  <!-- script/img 等标签的src属性请求时不存在跨域问题的,但是只支持GET请求。 -->

  <script src="http://localhost:3000/alluser?cb=testFunc"></script>


//后端代码
// JSONP跨域接口
router.get("/alluser", function (req, res, next) {
  let func = req.query.cb;
  model.find().exec((err, data) => {
    let result = JSON.stringify({
      err: "",
      status: "2000",
      data,
    });
    res.end(`${func}(${result})`);
  });
});

注意:以上三种配置,都是需要服务端参与的,服务器要进行配置,才能实现跨域,假如一个第三方接口禁止跨域请求,如何解决跨域问题呢?因为第三方接口,我们是拿不到服务器代码的。

  • 重点掌握:给你一个网站,如何找接口?
    1.确认接口的正确性,多方确认接口中的数据和页面上展示的数据是一致的;
    2.特别注意接口请求的方式,一般都是GET请求,也有是POST请求的;
    3.确认接口是否允许跨域;

  • 方式四:通过搭建本地代理服务器,实现第三方接口的跨域请求。
    命令:npm install http-proxy-middleware

//前端代码
 <button id="b3">csdn网</button>
  <button id="b4">百度</button>
  
  <script src="./jquery.min.js"></script>
  <script>
    $("#b3").click((e) => {
      $.ajax({
        type: "GET",
        url: "http://localhost:3000/csdn/api/articles?type=more&category=home&shown_offset=0",
        // https://blog.csdn.net/api/articles?type=more&category=home&shown_offset=0
        xhrFields: {
          withCredentials: true,
        },
        success: (data) => {
          console.log(data);
        },
        error: (err) => {
          console.log(err);
        }
      })
    });


    $("#b4").click((e) => {
      $.ajax({
        type: "GET",
        url: "http://localhost:3000/baidu/sugrec?prod=pc_his&from=pc_web&json=1&sid=34436_34379_31253_34375_33848_34450_34092_34111_26350_34428_22158_34390_34367&hisdata=%5B%7B%22time%22%3A1628318095%2C%22kw%22%3A%22%E9%87%91%E5%B1%B1%E6%89%93%E5%AD%97%E9%80%9A%22%7D%2C%7B%22time%22%3A1629198107%2C%22kw%22%3A%22%E5%88%9D%E5%A7%8B%E5%8C%96%E5%A4%B4%E5%83%8F%E5%9B%BE%E7%89%87%22%7D%2C%7B%22time%22%3A1629198111%2C%22kw%22%3A%22%E5%88%9D%E5%A7%8B%E5%8C%96%E5%A4%B4%22%7D%2C%7B%22time%22%3A1629253430%2C%22kw%22%3A%22mongodb%22%2C%22fq%22%3A2%7D%2C%7B%22time%22%3A1629253490%2C%22kw%22%3A%22mongdb%20%E4%B8%8B%E8%BD%BD%22%2C%22fq%22%3A2%7D%2C%7B%22time%22%3A1629254807%2C%22kw%22%3A%22mongdb%E5%8F%AF%E8%A7%86%E5%8C%96%E5%B7%A5%E5%85%B7%22%7D%2C%7B%22time%22%3A1629342971%2C%22kw%22%3A%22csdn%22%2C%22fq%22%3A7%7D%2C%7B%22time%22%3A1629357192%2C%22kw%22%3A%22http-proxy-middleware%22%7D%2C%7B%22time%22%3A1629358831%2C%22kw%22%3A%22%E7%99%BE%E5%BA%A6%E7%83%AD%E6%90%9C%22%2C%22fq%22%3A2%7D%2C%7B%22time%22%3A1629369847%2C%22kw%22%3A%22%E7%99%BE%E5%BA%A6%E7%BD%91%E7%9B%98%22%2C%22fq%22%3A8%7D%5D&_t=1629369850490&req=2&csor=0",
        // xhrFields里面的配置是设置发起ajax请求时,携带cookie的配置
        xhrFields: {
          withCredentials: true,
        },
        success: (data) => {
          console.log(data);
        },
        error: (err) => {
          console.log(err);
        }
      })
    });
  </script>
//后端代码
const express = require("express");
const { createProxyMiddleware } = require("http-proxy-middleware");
const cors = require("cors");

const app = express();
app.use(
  cors({
    origin: "http://127.0.0.1:5500",
    //设置跨域携带cookie的配置
    // credentials: true, // 注意:如果允许发送Cookie,origin也就是Access-Control-Allow-Origin这个配置项不允许为*
    // allowedHeaders: "Content-Type,Cookie",
  })
);
app.listen(3000, () => {
  console.log("服务已启动");
});

// 配置代理服务器
// 1. 想代理csdn的接口
const option1 = {
  target: "https://www.csdn.net", // 目标地址(域名)
  changeOrigin: true, // 是否将当前域名转化为target域名
  pathRewrite: {
    "^/csdn": "/", // 路径重写,将路径以"/csdn"开头的部分替换为"/"
  },
};
app.use("/csdn", createProxyMiddleware(option1));

// 2. 想代理百度的接口
const option2 = {
  target: "https://www.baidu.com", // 目标地址(域名)
  changeOrigin: true, // 是否将当前域名转化为target域名
  pathRewrite: {
    "^/baidu": "/", // 路径重写,将路径以"/baidu"开头的部分替换为"/"
  },
};
app.use("/baidu", createProxyMiddleware(option2));

跨域携带Cookie的问题

  • 跨域是不允许服务器给前端通过Set-Cookie传递Cookie信息的,除非服务器明确表示,可以向前端发送Cookie信息。
  • 跨域对于ajax请求而言,默认也是不允许在请求头中,携带Cookie信息的。
  • 前端如何配置ajax请求,允许携带Cookie信息:
//  默认情况下,标准的跨域请求是不会发送cookie的
 xhrFields: {
  withCredentials: true, // 允许请求携带凭证
 },
  • 后端的配置:
  app.use(
  cors({
    origin: "http://127.0.0.1:5500",
    credentials: true, // 注意:如果允许发送Cookie,origin也就是Access-Control-Allow-Origin这个配置项不允许为*
    allowedHeaders: "Content-Type,Cookie",
  })
);
Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐