You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MERN应用浏览器Cookie设置失败问题求助

MERN应用中Refresh Token Cookie无法在Application标签页显示的问题

我正在开发MERN应用,用户登录时会生成access_token和refresh_token两个令牌:access_token存入Redux状态,refresh_token计划存入浏览器Cookie。目前其他功能均正常,但Cookie仅能在Network标签页中查到,无法在Application标签页显示,已尝试多个本地浏览器。


后端代码

server.js

require('dotenv').config()
const express = require('express')
const app = express()
const cors = require('cors')
const cookieParser = require('cookie-parser')
const corsOption = require('./config/corsOption')
const PORT = process.env.PORT || 3500
const authHandler = require('./routes/authRoutes')


app.use(cookieParser(process.env.COOKIE_SECRET))
app.use(
    cors({
        credentials: true,
        origin: "http://localhost:3000",
    }))
app.use(express.json())


app.use('/',authHandler)

app.get('/',(req,res)=>{
    res.status(200).json({ 'message': 'Server responding successfully.'})
})

app.all("*",(req,res) => {
    res.status(404).json({'message':'Not found!'})
})

app.listen(PORT , ()=>{
    console.log(`Server is running in port ${PORT}`)
})

登录控制器(login controller)

const jwt = require('jsonwebtoken')
const dbConnections = require('../config/dbConnect')
const bcrypt = require('bcrypt')



const loginUser = async(req,res) =>{
    try{
        const database = await dbConnections()
        const collection = database.collection('users')

        const { email , password } = req.body

        if(!email || !password){
            return res
            .status(400)
            .json({ "message": "Failed. No empty field allowed!" })
        }

        if(!/^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/.test(email)){
            return res
            .status(404)
            .json({ "message": "Invalid email format!" })
        }
        const query = { email : email }
        const user = await collection.findOne(query)

        if(!user){
            return res
            .status(400)
            .json({
                "message":"No user found with this email. Please signup."
            })
        }

        const match = await bcrypt.compare(password,user.password)

        if(!match) {
            return res
            .status(400)
            .json({
                "message":"Invalid password!"
            })
        }

        const refresh_token = jwt.sign({ 
                email:email,
                role: user.role
            },
            process.env.REFRESH_TOKEN,
            {expiresIn: '2h'}
        )

        const access_token = jwt.sign({ 
                email:email,
                role: user.role
            },
            process.env.REFRESH_TOKEN,
            {expiresIn: '15m'}
        )


        res.cookie('refresh_token', refresh_token, {
            path: "/",
            sameSite: "none",
            httpOnly: true,
            secure: true,
        })

        res
        .status(200)
        .json({ 
            "access_token": access_token,
            "message": "Login successfully." 
        })

    }catch(err){
        console.log(err)
    }
}

前端代码

store.js

import { configureStore } from "@reduxjs/toolkit"
import authSlice from "../feature/auth/authSlice"
import { apiSlice } from "../app/api/apiSlice"

export const store = configureStore({
    reducer:{
        auth : authSlice,
        [apiSlice.reducerPath] : apiSlice.reducer,
    },
    middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(apiSlice.middleware)
})

apislice.js

import { createApi , fetchBaseQuery } from "@reduxjs/toolkit/query/react"


export const apiSlice = createApi({
    baseQuery: fetchBaseQuery({
        baseUrl: 'http://localhost:3500'
    }),
    credentials: 'include',
    tagTypes: [],
    endpoints: builder => ({})
}) 

authApiSlice.js

import { apiSlice } from "../../app/api/apiSlice";


export const authApiSlice = apiSlice.injectEndpoints({
    endpoints: builder =>({

        login: builder.mutation({
            query: ( credentials ) =>({
                url   : '/user/login',
                method: 'post',
                body  : credentials,
            })
        }),

    })
}) 

export const {
    useLoginMutation,
} = authApiSlice

authSlice.js

import { createSlice } from "@reduxjs/toolkit"

const initialState = {
    user : {},
}

export const authSlice = createSlice({
    name: 'auth',
    initialState,
    reducers: {
        logIn: (state,action) =>{
            state.user = action.payload
        },
        signUp: (credentials) =>{
            
        },
        logOut: () =>{

        }
    }
})


export const { logIn , logOut , signUp} = authSlice.actions
export default authSlice.reducer

问题原因及解决方法

核心问题

本地开发使用http://localhost(非HTTPS协议),但Cookie配置中设置了secure: true——该属性要求Cookie仅能通过HTTPS传输,HTTP环境下浏览器会拒绝保存此Cookie,因此Network标签能看到响应头里的Set-Cookie,但Application标签不会显示。

具体修复步骤

  1. 动态调整Cookie的secure和sameSite属性
    在登录控制器的res.cookie配置中,根据环境变量区分开发/生产环境:

    res.cookie('refresh_token', refresh_token, {
        path: "/",
        sameSite: process.env.NODE_ENV === 'production' ? "none" : "lax",
        httpOnly: true,
        secure: process.env.NODE_ENV === 'production',
        maxAge: 2 * 60 * 60 * 1000 // 可选,与JWT过期时间保持一致
    })
    
    • 生产环境(HTTPS):启用secure: true和sameSite: "none"
    • 开发环境(HTTP):设置secure: false,sameSite改为"lax"或"strict"("none"必须配合secure: true,否则浏览器会判定为无效配置)
  2. 验证配置一致性
    确认后端CORS的origin与前端地址完全匹配(当前代码已设置为http://localhost:3000,无需修改),且credentials: true已开启;前端RTK Query的credentials: 'include'配置正确(当前代码已设置)。

  3. 清理浏览器缓存
    清除浏览器中残留的无效Cookie后,重新测试登录流程。


内容的提问来源于stack exchange,提问作者Md Mahfuz Anam Tasnim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 06:25:03