動態

詳情 返回 返回

node作為後端的時候遇到的前端session無法保存的問題和解決辦法 - 動態 詳情

2023-07-18 更新

前後端分離項目建議還是使用token,也就是後端使用jsonwebtokenjwt進行token的生成和驗證,token不存在本地,存在客户端,隨請求頭一起帶來,安全性還是有保障

同時跨域問題建議還是後端進行解決,最好不要前端進行反向代理,容易出問題,由於我使用nodejs作為後端,解決跨域問題代碼如下:

//安裝cors庫
npm i cors

//app.js 或者index.js文件引入
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors())

既然後端解決了跨域問題,那麼前端這邊就不需要進行反向代理了,即package.json中的proxy一行可以去掉了,然後記得把請求的地址也直接指向後端地址

注意,有個很重要的一點就是,如果後端也是在本地的話,前端一定不要把請求的後端的地址寫成localhost

即下面這種寫法
const url = 'http://localhost:xxxx
這種寫法本地開發沒有問題,但是打包後的前端發送請求如果是這個地址話就會404,所以還是修改為const url = 'http://127.0.0.1:xxxx'這樣不論是開發環境還是生產環境都不會有請求錯誤的問題了


由於興趣使然 加薪 的想法,由於本人是個菜雞前端,想要學習後端,自然從自己最熟悉的語言javascript入手,所以開始學習nodejs,在b站上找到一個不錯的學習視頻
node學習
按照這個視頻的進度。中後期的時候我已經可以利用node+express+mongoose+mongondb搭建後端服務器創造接口對數據進行增刪改查了。
在利用session做登錄驗證的時候,遇到了第一個問題:
登錄成功以後,session沒有在瀏覽器中保存,後端的代碼中無法通過請求頭的session拿到預設的數據,導致一直處在未登錄狀態,同時數據庫中,每一次登錄都會增加一條session數據。
image.png

如下圖,現在是登錄成功的狀態,並且按照代碼,後端給響應頭添加了session相關數據
image.png

但是後面跟着的請求,並沒有攜帶這次的session,導致鑑權失敗
image.png

首先看看對應的代碼:

後端主要代碼如下:

const mongoose = require('mongoose');
const express = require('express');
const cors = require('cors');
const indexRouter = require('./routes/index');
const session = require('express-session');
const MongoStore = require('connect-mongo');

const app = express();
app.use(session({
    name:'sid',//設置cookie的name
    secret: 'secret',//參與加密的字符串(簽名)
    saveUninitialized: false,//是否每次請求都設置一個cookie用來存儲session的id
    resave:true,//是否在每次請求的時候重新保存session
    store: MongoStore.create({
        mongoUrl:'mongodb://127.0.0.1:xxxx/數據庫名'
    }),
    cookie:{
        httpOnly: true,//開啓後前端無法通過js操作session
        maxAge:60*1000*5//過期時間
    }
}))

app.use(express.json());//獲取請求體的中間件
app.use(cors())

首先是使用cors庫進行跨域相關操作
然後使用express-session庫進行session相關操作
使用connect-mongo庫搭配express-session進行數據庫的session寫入操作

下面是具體的api的處理,登錄請求來了以後,和數據庫中的用户數據進行對比,如果存在並且密碼正確,就在session中保存該次登錄的usernameid

router.post('/login', (req, response) => {
    UserModel.findOne({ username: req.body.username }).then(res => {
        console.log('登錄查詢成功',res)
        if(res){
            if(res.password===req.body.password){
                req.session.username= res.username;
                req.session._id=res._id;
                response.json({
                    code:'0000',
                    msg:'登錄成功',
                    data:res.username
                })
            }else{
                response.status(500).json({
                    code:'1001',
                    msg:'用户名或密碼錯誤',
                    data:null
                })
            }
        }else{
            response.status(404).json({
                code:'1001',
                msg:'用户不存在',
                data:null
            })
        }
    }).catch(err=>{
        console.log('登錄查詢失敗',err)
        response.status(500).json({
            code:'1001',
            msg:'登錄失敗',
            data:err
        })
    })
})

接下來就是book接口的代碼了:

router.get('/book', (req, res) => {
    console.log('session',req.session)
    if(req.session.username){
        console.log('已登錄')
        BooksModel.find().then((data) => {
            res.json({
                code: '0000',
                msg: '讀取成功',
                data: data
            })
        }).catch(err => {
            res.status(500).json({
                code: '1001',
                msg: '數據讀取失敗',
                data: err
            })
        })
    }else{
        console.log('未登錄')
        res.status(401).json({
            code:'1002',
            msg:'未登錄',
            data:null
        })
    }
})

接口很簡單,首先進行session的判斷,如果session沒有相關的用户信息,就判定為未登錄。

按照這一套邏輯下來,只要登錄成功了,session中就一定會有用户相關的信息,但是很遺憾,book的接口中,無論如何都沒有用户相關的信息,而且請求頭中也沒有Cookie的相關值。

所以我就百度
react 不攜帶 session的解決辦法
根據網上五花八門的回答折騰了很久,什麼前端要在axios中設置axios.defaults.withCredentials= true; 什麼後端要設置app.set('trust proxy', 1) 之類的,折騰了很久,這些

全部都沒有用

本人親測,全部都沒有用


最後思來想去,靈光一閃,最終找到了問題所在

後端設置了允許跨域,前端這邊直接請求後端,沒有經過代理,導致每一個請求,都是無法追蹤的請求,也就解釋了為什麼數據庫中每一次登錄成功,都會新增一條session數據,而不是覆蓋。
但是前端為什麼不能設置cookie我現在暫且矇在鼓裏。

知道了問題所在,那麼就着手解決問題。

後端那邊把關於跨域相關的代碼去掉,即不在需要cors庫相關的操作

前端這邊在package.json文件中設置proxy,直接代理到後端的服務器的地址
image.png

同時請求中的url地址需要變為前端自己的地址,例如本地啓動localhost:3000,那麼地址就需要設置為http://localhost:3000/
image.png

這樣就解決了明明登錄以後,前端請求還是沒有攜帶session相關信息的問題。

Add a new 評論

Some HTML is okay.