博客 / 詳情

返回

Egg.js使用redis實現跨域緩存(Fetch發送跨域請求)

前後端分離開發時,我們的前端請求是跨域請求,會造成session和cookie失效的問題。
在閲讀多種解決方法後,我選擇了使用redis來實現session的解決方案,確保前端使用跨域請求的情況下,後端可以維持用户session.

起因

為什麼選擇redis來實現跨域下的session呢?

我閲讀了多種跨域session丟失的解決辦法,但都沒有生效,於是最後選擇了redis才解決了這個問題。

前後端添加credential後,瀏覽器無法自動加載第三方cookie, 服務端的session和cookie仍然丟失。

前端Fetch跨域請求

const data = {key:"value"};// 參數
const myHeaders = new Headers();
myHeaders.append('Access-Control-Allow-Origin', 'http://localhost:3000/');
   // 設置Access-Control-Allow-Credentials,跨域請求帶授權
myHeaders.append('Access-Control-Allow-Credentials', 'true');
   // 設置mode為cors,進行跨域請求
myHeaders.append('mode', 'cors');
   // 設置Content-Type, 參數格式
myHeaders.append('Content-Type', 'application/x-www-form-urlencoded')
var urlencoded = new URLSearchParams()
for (let key in data) {
      urlencoded.append(key, data[key])
}
const requestOptions = {
      method: 'POST',
      headers: myHeaders,
      body: urlencoded,
      redirect: 'follow',
      // 設置為include確保跨域請求保持cookie
      credentials: 'include', 
}
fetch(api, requestOptions).then(response=>response.json());

Egg跨域配置

// config.default.js

'use strict'
const path = require('path')
module.exports = appInfo => {
  const config = {
        mode: 'file',
        errorHandler: {
          match: '/'
        },
  }

     // 設置security裏的csrf關閉,允許跨域請求
  config.security = {
        domainWhiteList: ['*'],
        csrf: {
          enable: false
        }
  }
  // 設置cors插件配置, origin為前端的來源(帶credentials無法設置為*)
  // 設置credentials為true,返回的Header帶有Access-Control-Allow-Credentials為true
  config.cors = {
        origin: 'http://localhost:3000',
        credentials: true,
        allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH'
  }
  // 這裏設置egg自帶的session,但跨域請求仍然丟失session
  config.session = {
        key: 'WheelFit',
        maxAge: 30 * 24 * 3600 * 1000, // 30 days
        httpOnly: true,
        encrypt: true,
        renew: true
  }

  // 自定義中間件, sessionToken為鑑權中間件,在收到請求後獲取session裏存儲的token
  config.middleware = ['sessionToken', 'errorHandler']

  return {
    ...config,
  }
}
// plugin.js
'use strict';
// 添加cors插件用於回覆跨域請求
// npm i --save egg-cors
module.exports = {
  cors: {
        enable: true,
        package: 'egg-cors',
     }
};

這個配置是在其他的解決跨域session丟失問題的文章中找到的,理論上添加credientals即可保持session,但我這裏並沒有生效,跨域請求仍然會丟失session,並且給response設置的cookie也不能被瀏覽器獲取到。但是使用postman,發送非跨域請求,是可以記錄的session的。


無奈我只能選擇使用redis維持跨域請求的session

Redis 配置

前端Fetch請求仍然保持不變(雖然credential已經不需要設置)
後端需要新增egg-redis插件

// plugin.js
'use strict';
// 添加cors插件用於回覆跨域請求
// npm i --save egg-cors
// npm i --save egg-redis
module.exports = {
  cors: {
        enable: true,
        package: 'egg-cors',
     },
  redis: {
    enable: true,
    package: 'egg-redis',
  },
};
// config.default.js
config.redis = {
  client: {
    port: 6379, // Redis port
    host: '127.0.0.1', // Redis host
    password: '',
    db: 0
  }
}

使用redis設置值

// login.js
async login(){
  const {ctx} = this;
  // login operation
  // login successfully
  const token = generateToken();
  ctx.app.redis.set(`token${userid}`, token);
  return (ctx.body={success:true, userid: userid})
}


// check session
async session_token() {
    const {ctx} = this;
    const {userid, token} = ctx.request.body;
    const redis_token = ctx.app.redis.get(`token${userid}`);
    if(redis_token === token) {
        return (ctx.body={success: true});
    }
    return (ctx.body={success: false});
}

這樣我們在服務端使用redis為跨域請求設置緩存狀態,我們還可以設置定時任務,刪除該狀態。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.