天天看點

ajax跨域的解決辦法跨域跨域的解決方式:後端如何配置跨域攜帶Cookie的問題

跨域

  • 跨域産生的原因

    當你由一個位址 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",
  })
);