Remix - 无法“设置 Cookie”除了当前路由的加载器的响应之外的任何地方

发布于 2025-01-12 05:25:16 字数 2275 浏览 3 评论 0原文

我有世界上最基本的混音应用程序设置来尝试找出 createStorageSessionCookies ,它们似乎只能在调用 API 的 UI 路由的加载器中设置。

示例:

  • 索引UI路由
  • API在routes/api/testApi.tsx(这是一个只有一个操作的资源路由)
  • app/session.server.ts,我使用createStorageSessionCookies()创建存储会话cookie

如果我尝试设置cookie除了 Index UI 路由中的加载程序返回之外的其他任何地方,它都不起作用。如果我调用 testApi 并尝试返回设置 cookie 的响应,则不起作用。如果我创建一个从加载程序调用的单独函数,并且该函数返回 API 调用的结果并尝试设置 cookie,则不起作用。实际上,只有当我在加载程序的响应中设置 cookie 时,它​​才有效。

示例索引路由在哪里工作

export const loader: LoaderFunction = async ({ request }) => {
    const session = await sessionStorage.getSession(
        request.headers.get('Cookie')
    );
    session.set('cookie_example', 'thisworks');
    return json(
        { status: 'this works' },
        {
            headers: {
                'Set-Cookie': await sessionStorage.commitSession(session),
            },
        }
    );
};

export default function Index() {
    const data = useLoaderData();

    return <div>hi</div>;
}

这不会工作

const setCookie = async (request: Request) => {
    const session = await sessionStorage.getSession(
        request.headers.get('Cookie')
    );
    session.set('cookie_example', 'thisdoesntwork');
    return json(
        { status: 'this doesnt work' },
        {
            headers: {
                'Set-Cookie': await sessionStorage.commitSession(session),
            },
        }
    );
}

export const loader: LoaderFunction = async ({ request }) => {
    const failFunc = await setCookie(request)
    return failFunc.json()
};

export default function Index() {
    const data = useLoaderData();

    return <div>hi</div>;
}

尝试从 API 路由设置它们也不会工作(从加载器或按钮调用的 app/routes/api/setCookie.tsx - 两者都不起作用)

export let loader: LoaderFunction = () => redirect('/');

export let action: ActionFunction = async ({ request }) => {
    const session = await sessionStorage.getSession(
        request.headers.get('Cookie')
    );
    session.set('cookie_example', 'does not work');

    return json(
        { status: 'does not work' },
        {
            headers: {
                'Set-Cookie': await sessionStorage.commitSession(session),
            },
        }
    );
};

I have the world's most basic remix app setup to try to figure out createStorageSessionCookies and it seems like they can only be set in the loader of the UI route that is calling the API.

Example:

  • Index UI route
  • API at routes/api/testApi.tsx (this is a resource route with only an action)
  • app/session.server.ts where I create the storage session cookie using createStorageSessionCookies()

If I try to set the cookie anywhere else except for the return from loader in the Index UI route, it doesn't work. If I call the testApi and try to return a response that sets the cookie, doesn't work. If I create a separate function that is called from the loader and that function returns the result of an API call and tries to set the cookie, doesn't work. It literally only works if I set the cookie in the response of the loader.

Example Index route where it works

export const loader: LoaderFunction = async ({ request }) => {
    const session = await sessionStorage.getSession(
        request.headers.get('Cookie')
    );
    session.set('cookie_example', 'thisworks');
    return json(
        { status: 'this works' },
        {
            headers: {
                'Set-Cookie': await sessionStorage.commitSession(session),
            },
        }
    );
};

export default function Index() {
    const data = useLoaderData();

    return <div>hi</div>;
}

This won't work

const setCookie = async (request: Request) => {
    const session = await sessionStorage.getSession(
        request.headers.get('Cookie')
    );
    session.set('cookie_example', 'thisdoesntwork');
    return json(
        { status: 'this doesnt work' },
        {
            headers: {
                'Set-Cookie': await sessionStorage.commitSession(session),
            },
        }
    );
}

export const loader: LoaderFunction = async ({ request }) => {
    const failFunc = await setCookie(request)
    return failFunc.json()
};

export default function Index() {
    const data = useLoaderData();

    return <div>hi</div>;
}

Also won't work trying to set them from an API route (app/routes/api/setCookie.tsx called from the loader or from a button - neither work)

export let loader: LoaderFunction = () => redirect('/');

export let action: ActionFunction = async ({ request }) => {
    const session = await sessionStorage.getSession(
        request.headers.get('Cookie')
    );
    session.set('cookie_example', 'does not work');

    return json(
        { status: 'does not work' },
        {
            headers: {
                'Set-Cookie': await sessionStorage.commitSession(session),
            },
        }
    );
};

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

饮惑 2025-01-19 05:25:16

当您正常返回 json() 时,为什么要对 setCookie 函数的响应调用 .json() 呢? https://remix.run/docs/en/v1/api/remix# json

Why are you calling .json() on the response from the setCookie function, when you just return json() normally. https://remix.run/docs/en/v1/api/remix#json

不气馁 2025-01-19 05:25:16

当您在返回 remix Responsejson 等的函数中提取一些代码时,您不能只返回 json(...)。你必须扔掉它;)

const setCookie = async (request: Request) => {
    const session = await sessionStorage.getSession(
        request.headers.get('Cookie')
    );
    session.set('cookie_example', 'thishouldwork');
    throw json(
        { status: 'this should work' },
        {
            headers: {
                'Set-Cookie': await sessionStorage.commitSession(session),
            },
        }
    );
}

检查这里的文档示例: https://remix.run/docs/en/v1/api/conventions#throwing-responses-in-loaders

对于你的最后一个片段,我不会创建一个 loader这只是重定向
因为在 action 之后 Remix 会触发 loader。也许它会产生意想不到的行为。

如果您想在此操作后重定向,请从按钮提交表单,如下所示:

<Form method="post" action="/api/setCookie">
 <button name="redirectTo" type="submit" value="/a-path-to-redirect" />
</Form>
export let action: ActionFunction = async ({ request }) => {
    const form = await request.formData();
    const redirectTo = formData.get("redirectTo");

    const session = await sessionStorage.getSession(
        request.headers.get('Cookie')
    );
    session.set('cookie_example', 'does not work');

    return redirect(
        redirectTo,
        {
            headers: {
                'Set-Cookie': await sessionStorage.commitSession(session),
            },
        }
    );
};

When you extract some code in function that return remix Response, json etc, you can't just return a json(...). You have to throw it instead ;)

const setCookie = async (request: Request) => {
    const session = await sessionStorage.getSession(
        request.headers.get('Cookie')
    );
    session.set('cookie_example', 'thishouldwork');
    throw json(
        { status: 'this should work' },
        {
            headers: {
                'Set-Cookie': await sessionStorage.commitSession(session),
            },
        }
    );
}

Check the doc example here : https://remix.run/docs/en/v1/api/conventions#throwing-responses-in-loaders

And for your last snippet, I would not create a loader that just redirect.
Because after an action Remix triggers loader. Maybe it create an unexpected behaviour.

If you want to redirect after this action, submit a form from your button like that :

<Form method="post" action="/api/setCookie">
 <button name="redirectTo" type="submit" value="/a-path-to-redirect" />
</Form>
export let action: ActionFunction = async ({ request }) => {
    const form = await request.formData();
    const redirectTo = formData.get("redirectTo");

    const session = await sessionStorage.getSession(
        request.headers.get('Cookie')
    );
    session.set('cookie_example', 'does not work');

    return redirect(
        redirectTo,
        {
            headers: {
                'Set-Cookie': await sessionStorage.commitSession(session),
            },
        }
    );
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文