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

生产环境下React应用localStorage无法设置但sessionStorage正常问题

生产环境下React应用localStorage无法设置但sessionStorage正常的问题

我开发了一个React应用,尝试在浏览器的localStorage中设置键值,同时也设置了sessionStorage。开发模式下运行应用时一切正常——能成功在sessionStorage和localStorage中设置键值。但在生产环境中,仅sessionStorage能成功设置。

组件代码

import React, { useEffect } from 'react';
import { useNavigate, useSearchParams } from 'react-router-dom';
import { connect } from 'react-redux';
import type { PayloadAction } from '@reduxjs/toolkit';
import type { IAutoAuthResponseData, ICliAuthResponseData } from '@exlint.io/common';

import { authActions } from '@/store/reducers/auth';
import type { IAuthPayload } from '@/store/interfaces/auth';
import BackendService from '@/services/backend';
import CliBackendService from '@/services/cli-backend';
import type { AppState } from '@/store/app';

import ExternalAuthRedirectView from './ExternalAuthRedirect.view';

interface IPropsFromState {
    readonly isAuthenticated: boolean | null;
}

interface PropsFromDispatch {
    readonly auth: (loginPayload: IAuthPayload) => PayloadAction<IAuthPayload>;
}

interface IProps extends IPropsFromState, PropsFromDispatch {}

const ExternalAuthRedirect: React.FC<IProps> = (props: React.PropsWithChildren<IProps>) => {
    const navigate = useNavigate();
    const [searchParams] = useSearchParams();

    const refreshToken = searchParams.get('refreshToken');
    const port = searchParams.get('port');

    useEffect(() => {
        if (refreshToken) {
            localStorage.setItem('token', refreshToken);

            const fetchResults = async () => {
                let autoAuthResponseData: IAutoAuthResponseData;

                try {
                    autoAuthResponseData = await BackendService.get<IAutoAuthResponseData>('/user/auth');

console.log(1);

                    sessionStorage.setItem('token', autoAuthResponseData.accessToken);
                } catch {
console.log(2);
                    localStorage.clear();

                    let navigateUrl = '/auth';

                    if (port) {
                        navigateUrl += `?port=${port}`;
                    }

                    navigate(navigateUrl);

                    return;
                }

                if (port) {
                    let cliToken: string;
                    let email: string;

                    try {
                        const responseData = await CliBackendService.get<ICliAuthResponseData>(
                            '/user/auth/auth',
                        );

                        cliToken = responseData.cliToken;
                        email = responseData.email;
                    } catch {
                        navigate(`/cli-auth?port=${port}`);

                        return;
                    }

                    try {
                        const res = await fetch(`http://localhost:${port}/${cliToken}/${email}`);

                        if (!res.ok) {
                            throw new Error();
                        }

                        navigate('/cli-authenticated');
                    } catch {
                        navigate(`/cli-auth?port=${port}`);

                        return;
                    }
                }

                props.auth({
                    id: autoAuthResponseData.id,
                    name: autoAuthResponseData.name,
                    createdAt: autoAuthResponseData.createdAt,
                });
            };

            fetchResults();
        } else {
            let navigateUrl = '/auth';

            if (port) {
                navigateUrl += `?port=${port}`;
            }

            navigate(navigateUrl);
        }
    }, [refreshToken, port]);

    useEffect(() => {
        if (!port && props.isAuthenticated) {
            navigate('/', { replace: true });
        }
    }, [port, props.isAuthenticated]);

    return <ExternalAuthRedirectView />;
};

ExternalAuthRedirect.displayName = 'ExternalAuthRedirect';
ExternalAuthRedirect.defaultProps = {};

const mapStateToProps = (state: AppState) => {
    return {
        isAuthenticated: state.auth.isAuthenticated,
    };
};

export default connect(mapStateToProps, { auth: authActions.auth })(React.memo(ExternalAuthRedirect));

关键细节

  • 已确认localStorage.setItem('token', refreshToken);代码执行:后续HTTP请求正常发起,且代码中的console.log(1)被打印(console.log(2)未触发)。
  • 生产环境浏览器控制台出现提示:Storage access automatically granted for First-Party isolation “https://api.exlint.io” on “https://app.exlint.io”,不确定是否与问题相关。
  • 存在一个登出时清除存储的Redux中间件,代码如下:
listenerMiddleware.startListening({
    actionCreator: authActions.setUnauthenticated,
    effect: () => {
        listenerMiddleware.stopListening({
            actionCreator: authActions.auth,
            effect: authEffect,
            cancelActive: true,
        });
        listenerMiddleware.startListening({
            actionCreator: authActions.auth,
            effect: authEffect,
        });

        localStorage.clear();
        sessionStorage.clear();
    },
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 20:15:39