前端跨域解決方案

前端跨域解決方案

跨域問題的產生及其價值意義

跨域(非同源策略請求),是由瀏覽器的安全機制引起的。
三者都一樣就是同源,只要有一個不同就是跨域

前端(跨域)的發展:

1、沒有專門的前端,由後端一起做。
2、前後端分開,部署的時候部署在同一個服務器,這樣就不存在跨域問題。但是,開發的時候前後端是分開的,還是會存在跨域,怎麼辦呢?有的公司要求前端也用idea進行開發,也就是前端代碼外面包一層java或其它後端代碼,運行的時候也要運行後端服務,這樣的做法給前端開發加大了難度。

  • 同源策略請求 ajax / fetch
  • 跨域傳輸

部署到web服務器上:同源策略

  • xampp 修改本地的host文件
127.0.0.1:1234  http://api.qq.com/

http://127.0.0.1:1234/index.html
http://api.qq.com/getData
3、前後端完全分離,分開開發,分開部署web服務器,data服務器,圖片服務器。 第三方開源的數據接口也會引起跨域(這樣的情況非常多)。

JSONP跨域解決方案的底層原理

  • script
  • img
  • link
  • iframe
  • ...
    =>不存在跨域請求的限制
<script src="https://cdn.bootcss.com/jquery/3.4.1/core.js"></script>
// 這個就是因爲script標籤沒有跨域限制,所以才能成功請求加載。

核心原理圖:
clipboard.png
react中子組件想要修改父組件中的狀態,也是傳遞一個回調函數給父組件,這個思想和JSONP的思想是一致的。

  • JSONP需要服務器端的支持
  • 問題:JSONP只能處理GET請求(放在?後面不安全,服務器返回的數據在瀏覽器會直接執行,如果是木馬修改的呢?也會直接執行,不安全)

舉例:

  • html頁面:1.jsonp.html
<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0">
</head>

<body>
  <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
  <script src="./1.jsonp.js"></script>
</body>

</html>
  • 1.jsonp.js
$.ajax({
    url: 'http://127.0.0.1:8001/list',
    method: 'get',
    dataType: 'jsonp', //=>執行的是JSONP的請求,這是jquery封裝的ajax的功能
    success: res => {
        console.log(res);
    }
});
  • 服務端配合:serverJSONP.js:
let express = require('express'),
    app = express();
app.listen(8001, _ => { // 監聽8001端口
    console.log('OK!');
});
app.get('/list', (req, res) => {
    let {
        callback = Function.prototype // callback如果沒有,默認爲空的函數
    } = req.query;
    let data = {
        code: 0,
        message: '返回jsonp請求的結果'
    };
    res.send(`${callback}(${JSON.stringify(data)})`); //=>後端需要處理好這樣的數據格式
});

CORS跨域資源共享

客戶端正常發送請求,服務端設置相關的頭信息。

  • 客戶端(發送ajax/fetch請求)
axios.defaults.baseURL = 'http://127.0.0.1:8888';
axios.defaults.withCredentials = true;
axios.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded';
axios.defaults.transformRequest = function (data) {
  if (!data) return data;
  let result = ``;
  for (let attr in data) {
    if (!data.hasOwnProperty(attr)) break;
    result += `&${attr}=${data[attr]}`;
  }
  return result.substring(1);
};
axios.interceptors.response.use(function onFulfilled(response) {
  return response.data;
}, function onRejected(reason) {
  return Promise.reject(reason);
});
axios.defaults.validateStatus = function (status) {
  return /^(2|3)\d{2}$/.test(status);
}
  • 服務器端設置相關的頭信息(需要處理options試探性請求)
app.use((req, res, next) => {
    res.header("Access-Control-Allow-Origin", "http://localhost:8000"); // http://localhost:8000是允許跨域請求的地址,如果允許很多地址跨域請求,設置爲"*"
    //=>*(就不能在允許攜帶cookie了) 具體地址
    res.header("Access-Control-Allow-Credentials", true);
    res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length,Authorization, Accept,X-Requested-With");
    res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,HEAD,OPTIONS");
    if (req.method === 'OPTIONS') {
        res.send('OK!');
        return;
    }
    next();
});

基於http proxy實現跨域請求

http proxy  =>webpack webpack-dev-server

修改webpack.config.js

let path = require('path');
let HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    mode: 'production',
    entry: './src/index.js',
    output: {
        filename: 'bundle.min.js',
        path: path.resolve(__dirname, 'build')
    },
    devServer: {
        port: 3000,
        progress: true,
        contentBase: './build',
        proxy: { // => 以'/'開始的請求,就把請求路徑轉到 target
            '/': {
                target: 'http://127.0.0.1:3001',
                changeOrigin: true // => 允許跨域
            }
        }
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html',
            filename: 'index.html'
        })
    ]
};

基於post message實現跨域處理

ngnix反向代理 =>不需要前端做什麼

基於iframe的跨域解決方案:

window.name / document.domin / location.hash

web scoket 和 nginx反向代理

socket.io

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章