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

React+Golang登录后Cookie页面刷新消失问题求助

登录状态无法维持:Cookie刷新后消失的排查方案

问题背景

我使用React作为前端、Golang作为后端,两者部署在同一VPS上:前端通过虚拟主机绑定域名,后端部署在VPS的8081端口Docker容器中。后端登录接口会设置存储JWT的Cookie,登录成功会弹出成功提示,但页面刷新后Cookie消失,无法维持登录状态,用户无法访问个人资料等功能。

相关代码

后端Login接口处理代码

func (app *application) Login(w http.ResponseWriter, r *http.Request) {
    if r.Method != "POST" {
        w.Header().Set("Allow", "POST")
        http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
        return
    }

    var User UserLoginBody
    decoder := json.NewDecoder(r.Body)
    if err := decoder.Decode(&User); err != nil {
        app.server_error(w, err)
        return
    }

    userID, err := app.users.Authenticate(User.Email, User.Password)
    if err != nil {
        app.server_error(w, err)
        return
    }
    fmt.Println("User ID:", userID)
    tokenString, err := app.user_helpers.GenerateToken(userID)
    if err != nil {
        println(userID, tokenString)
        app.server_error(w, err)
        return
    }

    http.SetCookie(w, &http.Cookie{
        Name:     "token",
        Value:    tokenString,
        MaxAge:   3600,
        HttpOnly: false,
        Secure:   true,
        SameSite: http.SameSiteNoneMode,
    })

    w.WriteHeader(http.StatusOK)
}

前端登录请求代码

const LoginForm = () => {
  const form = useForm<SignInSchemaType>({
    resolver: zodResolver(SignInSchema),
    defaultValues: {
      userEmail: "",
      userPassword: "",
    }
  })
  const navigate = useNavigate();
  const { toast } = useToast()
  const [isPassword, setIsPassword] = useState(true);

  const handleLogin = async (values: SignInSchemaType) => {
    try {
      const response = await fetch("https://cihanbatasul.com:8081/login", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(values),
        credentials: "include",
      });
      if (!response.ok) {
        toast({
          variant: "destructive",
          title: "Failure",
          description: "There was a problem with the login. PLease make sure you have the right credentials."
        })
      }
      if (response.ok) {
        toast({
          variant: "default",
          title: "Success",
          description: "Welcome back!"
        })
        navigate(-1);
      }
    } catch (error) {
      console.log(error)
      toast({
        variant: "destructive",
        title: "Failure",
        description: "There was a problem with the login. PLease make sure you have the right credentials."
      })
    }
  }

  return (
    <motion.div
      key="login-form"
      initial={{ opacity: 0, scale: 0 }}
      animate={{ opacity: 1, scale: 1 }}
      exit={{ opacity: 0, scale: 0 }}
      transition={{ duration: 0.6, ease: easeInOut }}
      className="w-full h-full flex flex-col gap-3 text-inherit  p-3 md:p-6 lg:p-12"
    >
      <Form  {...form}>
        <form onSubmit={form.handleSubmit(handleLogin)} className="space-y-8">
          <FormField control={form.control} name="userEmail" render={({ field }) => (
            <FormItem>
              <FormControl>
                <Input LabelText="Email" type="email" {...field} />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
          />
          <FormField control={form.control} name="userPassword" render={({ field }) => (
            <FormItem>
              <FormControl>
                <PasswordInput
                  {...field}
                  fullWidth={true}
                  PlacerholderText="Password"
                  isPassword={isPassword}
                  onVisible={setIsPassword}
                />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
          />
          <Button className="w-full bg-blue-600 rounded-lg hover:bg-blue-700 py-2 text-white cursor-pointer" type="submit">Submit</Button>
        </form>
      </Form>
    </motion.div>
  );
};

export default LoginForm;

前端获取Cookie代码

const getJwtFromCookie = () => {
    const cookieValue = document.cookie
        .split('; ')
        .find(row => row.startsWith('token='))
        ?.split('=')[1];
    return cookieValue;
};

const token = getJwtFromCookie()
if (token) {
    dispatch(setToken(token))
}
const isUserLoggedIn = useSelector((state: RootState) => state.user.isLoggedIn)

Redux的userSlice代码

import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import {ShelvesResponse } from "@/views/UserProfile";
interface User {
    userID?: string | null  
    isLoggedIn: boolean
    token: string | null
    userName: string 
    shelves: ShelvesResponse
    recommendations: string[]
    authors: string[] 
}

const initialState: User = {
    userID: null, 
    isLoggedIn: false,
    token: null,
    userName: "",
    shelves: {
        userName: "User",
        AllShelves: [
          {
            shelfType: "curr",
            shelf: [
              {
                bookID: "1",
                title: "Current Book",
                author: "Author 1",
                description: "Description of the current book",
                picture: "url-to-book-image",
                added_at: Date()
    
              },
            ],
          },
          {
            shelfType: "fav",
            shelf: [
              {
                bookID: "2",
                title: "Favorite Book",
                author: "Author 2",
                description: "Description of the favorite book",
                picture: "url-to-book-image",
                added_at: Date()

              },
            ],
          },
          {
            shelfType: "wtr",
            shelf: [
              {
                bookID: "3",
                title: "Want to Read Book",
                author: "Author 3",
                description: "Description of the want to read book",
                picture: "url-to-book-image",
                added_at: Date()

              },
            ],
          },
          {
            shelfType: "read",
            shelf: [
              {
                bookID: "4",
                title: "Read Book",
                author: "Author 4",
                description: "Description of the read book",
                picture: "url-to-book-image",
                added_at: Date()

              },
            ],
          },
        ],
      },    
      recommendations: [],
      authors: []  
}

const userSlice = createSlice({
    name: "user", 
    initialState,
    reducers: {
      setAuthors: (state, action: PayloadAction<string[]>) => {
      state.authors = action.payload
    },
      setRecommendations: (state, action:PayloadAction<string[]>) => {
        state.recommendations = action.payload
      },
        setShelves: (state, action: PayloadAction<ShelvesResponse>) => {
            state.shelves = action.payload
        },
        setToken: (state, action: PayloadAction<string>) =>{
            state.token = action.payload
            state.isLoggedIn = !!action.payload
            console.log(state.token)
        },
        logoutUser: (state) => {
            document.cookie = "token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"        
            state.token = null
            state.isLoggedIn = false 
        },
        setID: (state, action: PayloadAction<string>) => {
            state.userID = action.payload
        }
    }
})

export const {setToken, logoutUser, setID, setShelves, setRecommendations, setAuthors} = userSlice.actions

export default userSlice.reducer

登录后浏览器截图

登录后Cookie截图
登录后请求截图

排查原因及修复方案

  • Cookie未绑定正确域名
    当前后端设置Cookie时未指定Domain属性,浏览器默认将Cookie绑定到带端口的域名cihanbatasul.com:8081,而前端域名是不带端口的cihanbatasul.com,跨端口场景下前端无法读取该Cookie。
    修复:在后端Cookie配置中添加Domain: "cihanbatasul.com",让Cookie绑定到根域名,确保前端页面能读取。

  • Cookie路径限制
    默认Path为请求路径/login,导致只有/login路径下能访问Cookie,其他页面无法读取。
    修复:添加Path: "/",使Cookie在整个域名下生效。

  • 前端获取Cookie时机优化
    当前获取Cookie的代码仅在组件初始化时执行,若页面刷新时Cookie读取逻辑未触发,会导致Redux状态未更新。
    修复:将获取Cookie的逻辑放入useEffect钩子,确保页面刷新时重新读取:

    useEffect(() => {
      const token = getJwtFromCookie();
      if (token) {
        dispatch(setToken(token));
      }
    }, []);
    
  • 确认Secure属性兼容性
    虽然当前是HTTPS环境,但若存在非HTTPS请求场景,Secure: true会阻止Cookie设置。需确保所有请求均为HTTPS。

  • 检查Docker端口映射与反向代理
    确认后端Docker容器端口映射正确,若前端使用Nginx等反向代理,需确保代理配置正确传递Set-Cookie响应头,未修改或丢失Cookie属性。

内容的提问来源于stack exchange,提问作者intero

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 21:59:53