localStorage 未在生产环境中设置,但在本地主机上

问题描述 投票:0回答:1

我创建了一个 React 应用程序,我尝试在浏览器的本地存储中设置一些键。我还设置了会话存储。当我在开发模式下运行我的应用程序时,它可以正常工作——我成功地在会话和本地存储中设置了密钥。然而,在生产中,只有会话存储成功设置.

这是我的代码:

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');

                    sessionStorage.setItem('token', autoAuthResponseData.accessToken);
                } catch {
                    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 请求从我的浏览器传出(并且代码确实在这行代码之后调用 HTTP 请求,如您所见)。

同样的代码,出于某种原因,没有设置本地存储。但是,您可以在接下来的代码行中看到,我还设置了会话存储:

sessionStorage.setItem('token', autoAuthResponseData.accessToken);
。然后,会话存储成功设置也在生产.

当我在生产环境中的浏览器中检查我的控制台时,我看到这条消息:

Storage access automatically granted for First-Party isolation “https://api.exlint.io” on “https://app.exlint.io”.
。不确定它有多相关。

javascript reactjs browser local-storage
1个回答
0
投票

存储绑定到源(域/协议/端口)。这意味着不同的协议或子域定义了不同的存储对象,它们不能访问彼此的数据。

我相信在生产模式下,问题与更改子域有关(app.exlint.io / app.exlint.io)。在 navigate() 调用之后,对 localStorage.getItem 的调用转到与另一个子域关联的 LocalStorage 对象。

我发现了一个 stackoverflow 问题,它有一个解决您问题的示例。解决方案是使用 iframe 和 postMessage 通过父域访问“共享”存储。

© www.soinside.com 2019 - 2024. All rights reserved.