1. 程式人生 > >axios 簡易攔截器

axios 簡易攔截器

引入

  • 先從我為什麼要寫這個無聊又沒有挑戰的攔截器開始說吧。昨天一同學問了我一個問題:“誒,大哥啊,你那個後臺管理系統demo為什麼要設定攔截器,這個攔截器是幹嘛用的?”
  • 我的回答很簡單,因為這個問題實際上真的很簡單:“攔截器就是在你的請求要做接下來的處理時,多一次或多次驗證。例如:你寫了幾個請求資料的介面,開啟服務後,使用者沒登入直接訪問這些介面,也是可以拿到資料的,但這就違背了後臺管理系統必須先登入的原則,有心人就會利用這個bug來竊取你的資料庫資料了”
  • 說白了,攔截器就是起一個攔截作用嘛
  • 說到這裡,左前後端互動的同學們都注意了哈,前後臺互動一定要遵循一個原則:互不信任原則。怎麼說呢,就是前端傳送到後臺的引數(必須在前端驗證合法的才能傳送),後臺必須驗證是否合法(是否符合該引數的原定資料型別和值範圍),後臺返回給前端的資料,也必須驗證是否為約定的資料結構和值型別。

進入正題 —- 前端的攔截器原理和實現

  • 上面也說到了,攔截器就是在你的請求要做接下來的處理時,多一次或多次驗證。先看一段示例:前端的攔截器怎麼寫(這裡引用第三方的ajax庫 –> axios,其他ajax庫可參考)
    // http請求攔截
    axios.interceptors.request.use(config => {
        if (config.method == 'post' && config.url != '/login') {
            config.data = {
                ...config.data,
                ...
{"user": "admin"}, ...{ "datetime": new Date() } } } else if (config.method == 'get') { if (/\?/.test(config.url)) { config.url += 'user=admin&datetime=' + new Date(); } else { config.url += '?user=admin&datetime='
+ new Date(); } } return config; }); // http響應攔截 axios.interceptors.response.use(response => { switch (response.data.requestIntercept) { case 1: console.log('登入資訊已失效,請重新登入!'); } return response; });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 這個示例中設定了前端向服務端發起請求時的http請求攔截和服務端返回資料時的http響應攔截,interceptors是axios的一個攔截器物件,axios.interceptors.request是對http請求攔截配置的物件,這裡我設定了給每個請求新增一個系統當前的時間和一個使用者名稱(實際專案中新增使用者名稱變數),這樣可以避免get請求出現304,並且每次發起請求都向伺服器傳送一次使用者名稱,axios.interceptors.response是對http響應攔截配置的物件,這裡如果伺服器返回json為{requestIntercept: 1},則判定伺服器拒絕了頁面的http請求的執行,直接返回一個狀態提示,否則就返回正常的 response。
  • 前端這樣設定了攔截器就一勞永逸了嗎?當然不是的,前端的永遠不是安全的

安全級別的攔截器 —- nodejs服務端的攔截器原理和實現

  • 服務端的攔截器才是安全的,先看下面這段簡單的攔截器程式碼,主要攔截的是沒有使用者名稱或有使用者名稱但在服務端沒有對應的session的http請求
    // 攔截器
    app.all('/*', function (req, res, next) {
        if (req.url == '/login') {
            next();
        } else {
            if (req.method == "GET") {
                username = req.query.user;
            } else if (req.method == "POST") {
                username = req.body.user;
            }
            if (sessionPool[username] && getSid(res.req.headers.cookie) == sessionPool[username]) {
                // 使用者session存在
                next();
            } else {
                res.json({ requestIntercept: 1 });  // 頁面拿到這個值在做攔截處理即可
            }
        }
    });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • app.all(‘/*’),這裡的app是 express() 物件,app.all() 是針對所有的http請求, ‘/*’匹配的是所有以“/”開頭的http請求,後面執行的實際上相當於是一個介面,三個引數分別是request,response,next,其中next是攔截器通過的回撥函式
  • 這裡的思路就是先判斷請求是否為登入介面,不是的話就取出請求中的user引數,用這個user去驗證兩邊的cookie是否相同,若不同則直接返回{ requestIntercept: 1 }這個json,告訴前端驗證不通過;驗證通過的呼叫next()回撥函式進入下一個處理環節 — 資料讀取介面

完整的前後端互動攔截器示例:

  • 完整的攔截器設定:(以 /getlist 介面為例)

    1. 前端發起/getlist 介面的http請求,攔截並驗證請求
    2. 服務端通過app.all(‘/*’),匹配到/getlist 介面是 /* 開頭的請求,立即攔截/getlist 介面的http請求並驗證
    3. 驗證通過後,呼叫next()方法將後續處理交給 app.('/getlist') 處理
    4. app.('/getlist') 處理完成後返回資料給前端
    5. 前端驗證返回的json資料是不是{requestIntercept: 1},若不是則交給 axios.post('/getList').then() 處理,至此一次http請求完成,若返回的json資料是{requestIntercept: 1},那麼在 axios.interceptors.response 就會被攔截,同時會告知axios.post('/getList') 物件將promise物件的狀態由 pending(promise正在非同步執行中) 改為 resolved(promise執行完畢)
  • 前端: index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>login</title>
        <style>
            * {
                margin: 0;
                padding: 0;
            }
            input {
                -web-kit-appearance: none;
                -moz-appearance: none;
                font-size: 1.4em;
                height: 2em;
                margin: 0.5em 0;
                border-radius: 4px;
                border: 1px solid #c8cccf;
                color: #6a6f77;
                outline: 0;
            }
            input:focus {
                border: 1px solid #ff7496;
            }
            input[type="button"]:focus {
                background-color: #999999;
            }
            .login-form {
                width: 25%;
                margin: 100px auto;
                line-height: 3em;
            }
            .login-form input,
            .login-form button {
                width: 100%;
            }
        </style>
    </head>

    <body>
        <div id="app" class="login-form">
            <input type="username" v-model="user">
            <input type="password" v-model="pwd">
            <input type="button" value="登入" @click="login">
            <input type="button" value="獲取資料" @click="getList">
            <input type="button" value="登出" @click="logout">
        </div>
        <script type='text/javascript' src='./js/vue.min.js'></script>
        <script src="https://cdn.bootcss.com/axios/0.16.2/axios.min.js"></script>
        <script type='text/javascript'>
            // http請求攔截
            axios.interceptors.request.use(config => {
                if (config.method == 'post' && config.url != '/login') {
                    config.data = {
                        ...config.data,
                        ...{ "user": "admin" }
                    }
                } else if (config.method == 'get') {
                    if (/\?/.test(config.url)) {
                        config.url += 'user=admin'
                    } else {
                        config.url += '?user=admin'
                    }
                }
                return config;
            });

            // http響應攔截
            axios.interceptors.response.use(response => {
                switch (response.data.requestIntercept) {
                    case 1:
                        console.log('登入資訊已失效,請重新登入!');
                }
                return response;
            });
            let Vm = new Vue({
                el: '#app',
                data() {
                    return {
                        user: 'admin',
                        pwd: 'admin'
                    }
                },
                methods: {
                    login() {
                        const that = this;
                        axios.post('/login', {
                            "user": that.user,
                            "pwd": that.pwd
                        }).then((res) => {
                            console.log(res.data);
                            if (res.data.status == 1) {
                                alert('登陸成功!');
                            }
                        }).catch((err) => {
                            console.log('出錯了-,-!', err);
                        })
                    },
                    getList() {
                        axios.post('/getList', {
                            // "user": "admin"
                        }).then((res) => {
                            console.log(res.data);
                        }).catch((err) => {
                            console.log('出錯了-,-!', err);
                        })
                    },
                    logout() {
                        axios.post('/logout', {
                            // "user": "admin"
                        }).then((res) => {
                            console.log(res.data);
                            if (res.data.logout == 1) {
                                alert('登出成功');
                            }
                        }).catch((err) => {
                            console.log('出錯了-,-!', err);
                        })
                    }
                }
            })
        </script>
    </body>
    </html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 服務端:app.js
    const express = require('express');
    const bodyParser = require('body-parser');
    const fs = require('fs');
    const path = require('path');
    const mysql = require('mysql');

    const app = express();
    app.use(express.static(path.resolve(__dirname, './www')));  // 預設首頁為www下的index.html
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({ extend: true }));

    const sessionPool = {};

    const pool = mysql.createPool({
        host: 'mysql資料庫IP',
        user: 'mysql連線使用者,最高許可權使用者為root',
        password: '填寫你的密碼',
        port: '資料庫埠,預設3306',
        database: '使用的mysql資料庫名',
        multipleStatements: true
    });

    // 攔截器
    app.all('/*', function (req, res, next) {
        let url = req.url;
        if (url == '/login') {
            next();
        } else {
            if (req.method == "GET") {
                username = req.query.user;
            } else if (req.method == "POST") {
                username = req.body.user;
            }
            if (sessionPool[username] && getSid(res.req.headers.cookie) == sessionPool[username]) {
                // 使用者session存在
                next();
            } else {
                res.json({ requestIntercept: 1 });  // 頁面拿到這個值在做攔截處理即可
            }
        }
    });

    // 請求錯誤
    app.get('/error', function (req, res) {
        res.send(fs.readFileSync(path.resolve(__dirname, './www/error.html'), 'utf-8'))
    });

    // 測試介面
    app.get('/', function (req, res) {
        res.json({ test: `測試伺服器正常!` });
    })

    // 登入介面
    app.post('/login', function (req, res) {
        // 判斷是否已線上
        if (sessionPool[req.body.user]) {
            // 線上
            delete sessionPool[req.body.user];
        }
        // 使用資料庫連線池
        pool.getConnection(function (err, connection) {
            // 多語句查詢示例
            connection.query("select * from userlist where username = '" + req.body.user + "' and password = '" + req.body.pwd + "' and delMark = '0'; select count(1) from userlist", function (err, rows) {
                if (err) {
                    throw err;
                } else {
                    if (rows[0].length > 0) {
                        // 設定cookie
                        let cookieSid = req.body.user + Date.parse(new Date());
                        res.setHeader("Set-Cookie", ["sid=" + cookieSid + ";path=/;expires=" + new Date("2030")]);
                        // 先儲存session到sessionPool
                        sessionPool[req.body.user] = cookieSid;
                        // 返回登入成功的資訊
                        res.json({ status: 1, dbData: rows[0], session: req.session });
                        res.end();
                    } else {
                        // 使用者不存在
                        res.json({ status: 0 });
                        res.end();
                    }
                }
            });
            // 釋放本次連線
            connection.release();
        });
    })

    // 退出登入
    app.post('/logout', function (req, res) {
        delete sessionPool[req.body.user];
        res.json({ logout: 1 });
        res.end();
    })

    app.post('/getList', function (req, res) {
        pool.getConnection(function (err, connection) {
            connection.query('select * from userlist', function (err, rows) {
                if (err) {
                    throw err;
                } else {
                    res.json({ list: rows });
                    res.end();
                }
            });
            connection.release();
        })
        console.log('session池 ', sessionPool);
    });

    app.listen(8000, function () {
        console.log('[email protected] 0.0.0.0:8000 succeed');
    })

    /*
    * 公共方法
    */

    // 解析cookie中的sid
    function getSid(cookieStr) {
        let sid = '', cookieArr = cookieStr.split(';');
        for (let i = 0; i < cookieArr.length; i++) {
            if (cookieArr[i].trim().substring(0, 3) == 'sid') {
                return sid = cookieArr[i].trim().substring(4, cookieArr[i].length);
            }
        }
        return sid;
    }

相關推薦

axios 簡易攔截

引入先從我為什麼要寫這個無聊又沒有挑戰的攔截器開始說吧。昨天一同學問了我一個問題:“誒,大哥啊,你那個後臺管理系統demo為什麼要設定攔截器,這個攔截器是幹嘛用的?”我的回答很簡單,因為這個問題實際上真的很簡單:“攔截器就是在你的請求要做接下來的處理時,多一次或多次驗證。例如

axios 全域性攔截 (相應和請求)

axios.interceptors.request.use(function (config) { // 在傳送請求之前做些什麼 return config; }, function (error) { // 對請求錯誤做些什麼 return Promise.reject(error); }); // 新增

axios請求,攔截的使用

  1. axios 建立請求    import axios from 'axios'    import {Message} from 'element-ui'    import router from "../router/index";    /** axios建立例項*/    let http=

vue axios 登入攔截

1.安裝 vue-cookiescnpm install vue-cookies --save2.在登入介面中 設定cookies this.$http.post(global.domain + '/login/check',   { username:  this.rul

axios請求攔截

問題: 訪問某個地址頁面時,會被要求重新登入後在訪問,身份認證失效了 token問題: 1:token丟失 2:token本地存在,但是卻失效了 所以不可以只判斷是否token存在 請求時伺服器返回的是401錯誤,授權出錯,也就是沒有權利訪問該頁面。 解決問題:

axios使用攔截統一處理所有的http請求

axios使用攔截器 在請求或響應被 then 或 catch 處理前攔截它們。 http request攔截器 // 新增請求攔截器 axios.interceptors.reque

axios踩坑記錄+攔截使用+vue cli代理跨域proxy

dex ios文檔 exports 地址 必須 主頁 mon 空白 space 1、小小的提一下vue cli腳手架前端調後端數據接口時候的本地代理跨域問題,如我在本地localhost訪問接口http://40.00.100.100:3002/是要跨域的,相當於瀏覽器設置

.NET 簡易方法攔截

parameter hid 接口 tle 說過 inf img 異常 肩膀 偉大的無產階級Willaim曾說過:"無論你覺得自己多麽的了不起,也永遠有人比你更強"。對,我說過!我就是william。 今天想記錄一下在項目中遇到的一個比較有意思的

Axios 攔截 取消請求

調用 span n) iso 我們 信息 mes === pan axios 最常用的功能之一,攔截器 axios.interceptors.response.use( response => { let {data: json} = response

axios攔截

error resolv meta use err fig home screen lai // 引入axios以及element ui中的loading和message組件 import axios from ‘axios‘ import { Loading, Messa

axios攔截

發送請求 json 啟動文件 text 去掉 col 文件 log 添加 在這個vue項目中在啟動文件main.js中給axios配置了攔截器,此處配置後它就是全局的。在請求前會出現一個動態的loading圖,在響應後隱藏此loading圖。 這非常好用。在每個頁面的請求數

axios攔截搭配token使用

在瞭解到cookie、session、token的作用後學習token的使用 cookie是隨著url將引數傳送到後臺,安全性最低,並且大小受限,不超過4kb左右,它的資料儲存在客戶端 session資料儲存在服務端,在記憶體中開闢空間儲存資料,session檔名即sessionID儲存在cookie內,

vue cli+axios踩坑記錄+攔截使用,代理跨域proxy(更新)

1、首先axios不支援vue.use()方式宣告使用,看了所有近乎相同的axios文件都沒有提到這一點  建議方式 在main.js中如下宣告使用 import axios from 'axios'; Vue.prototype.$axios=axios; 那麼在其他vue元件中就可

vue cli+axios踩坑記錄+攔截使用,代理跨域proxy

1、首先axios不支援vue.use()方式宣告使用,看了所有近乎相同的axios文件都沒有提到這一點 建議方式 2.小小的提一下vue cli腳手架前端調後端資料介面時候的本地代理跨域問題,如我在本地localhost訪問介面http://40.00.100.100:3002/是要跨域的,

Vue2.x -Axios請求,攔截

不得不說不管是微信小程式還是Web,封裝的請求使用起來確實很方便,起碼能讓程式碼看起來清晰,不那麼冗餘,不過最重要還是能少寫幾行程式碼。哈哈 1.建立Vue模板專案:進入專案下, npm install axios 2.開啟專案進入min.js,將他們掛載到全域性中,方便使用。

vue中axios攔截的使用

1.攔截器分為request請求攔截器和response響應攔截器 PS:request請求攔截器:傳送請求前統一處理,如:設定請求頭headers、應用的版本號、終端型別等。 response響應攔截器:有時候我們要根據響應的狀態碼來進行下一步操作,例如:由於當前的token過期,

細說vue axios登入請求攔截

當我們在做介面請求時,比如判斷登入超時時候,通常是介面返回一個特定的錯誤碼,那如果我們每個介面都去判斷一個耗時耗力,這個時候我們可以用攔截器去進行統一的http請求攔截。 1.安裝配置axios cnpm install --save axios 我們可以建一個js檔案來做這個統一的處理,新建一個axio

axios post 請求tomcat,攔截獲取不到getInputStream流中的資料

今天做專案,前端的大佬用axios傳送post請求,而我要利用過濾器和攔截器進行許可權的校驗,校驗的內容就是上送的某個欄位的內容,所以我們需要重寫request請求(request請求只能獲取一次,如果在攔截器中獲取,那麼控制器就獲取不到相應的引數),並且在攔截器中進行校驗,

細說vue axios登錄請求攔截

url catch 聊天 不足 creat fun lose req clas 當我們在做接口請求時,比如判斷登錄超時時候,通常是接口返回一個特定的錯誤碼,那如果我們每個接口都去判斷一個耗時耗力,這個時候我們可以用攔截器去進行統一的http請求攔截。 1.安裝配置axio

vue axios攔截介紹

axios的攔截器是一個作用非常大,非常好用的東西。分為請求攔截器和響應攔截器兩種。我一般把攔截器寫在main.js裡。 1. 請求攔截器 請求攔截器的作用是在請求傳送前進行一些操作,例如在每個請求體里加上token,統一做了處理如果以後要改也非常容易。 axios.interceptors.requ