在 TRPC 获取处理程序中访问 Cookies

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

我正在我的 TRPC Nextjs 应用程序中构建基于令牌的身份验证。我将刷新令牌存储在用户 cookie 中。如果请求因访问令牌过期而失败,我想访问我的 API 路由以生成新的访问令牌。我无法理解如何在 TRPC 获取中访问 cookie(在我的情况下是刷新令牌)针对每个请求运行的处理程序。 (它显然运行客户端)

import {  httpBatchLink, loggerLink } from "@trpc/client";
import { createTRPCNext } from "@trpc/next";
import { type inferRouterInputs, type inferRouterOutputs } from "@trpc/server";
import superjson from "superjson";
import { type AppRouter } from "@/server/api/root";

export let token: string;

export const setToken = (newToken: string) => {
  token = newToken;
};

{... ...}

export const api = createTRPCNext<AppRouter>({
  config({ctx}) {
    return {
      links: [
        loggerLink({
          ...
        }),

        httpBatchLink({
          transformer: superjson,
          url: `${getBaseUrl()}/api/trpc`,
          headers: ({
          }) => {
            const newHeaders = new Headers();
          
            if(token) newHeaders.set("Authorization", `Bearer ${token}`);
            return newHeaders;
          },
          fetch(url, options) {

            //I need to access the cookies here
            //Ctx is undefined
            
            return fetch(url, {
              ...options,
              credentials: "include",
            });
          },

        }),
        
      ],
      
    };
  },
  ssr: false,
  transformer: superjson,
   
});
{... ...}

我尝试使用像

js-cookie
这样的包,但这不起作用,因为代码不在实际的 React 组件中运行。我还尝试访问包含在
config({ctx})
中传递的标头的 ctx,但它始终是未定义的

authentication next.js cookies react-query trpc
1个回答
0
投票

在页面路由器中,我们只能在

headers
getServerSideProps
中访问
getInitialProps
。如果您想使用 tRPC 访问标头,您应该启用其
ssr
标志,如官方文档中所述:https://trpc.io/docs/client/nextjs/ssr

会是这样的:

import { httpBatchLink } from '@trpc/client';
import { createTRPCNext } from '@trpc/next';
import { ssrPrepass } from '@trpc/next/ssrPrepass';
import superjson from 'superjson';
import type { AppRouter } from './api/trpc/[trpc]';

export const trpc = createTRPCNext<AppRouter>({
  ssr: true, // enabled it here
  ssrPrepass,
  config(opts) {
    const { ctx } = opts;
    if (typeof window !== 'undefined') {
      // during client requests
      return {
        links: [
          httpBatchLink({
            url: '/api/trpc',
          }),
        ],
      };
    }

    return {
      links: [
        httpBatchLink({
          url: `${getBaseUrl()}/api/trpc`,
          headers() {
            // access headers here:
            if (!ctx?.req?.headers) {
              return {};
            }
            // To use SSR properly, you need to forward client headers to the server
            // This is so you can pass through things like cookies when we're server-side rendering
            return {
              cookie: ctx.req.headers.cookie,
            };
          },
        }),
      ],
    };
  },
});

但是,也有人说:

启用 SSR 时,tRPC 将使用

getInitialProps
预取服务器上的所有查询。当您使用 getServerSideProps 时,这会导致像
this
这样的问题,而解决它是我们无法解决的。

或者,您可以禁用 SSR(默认)并使用 Server-Side Helpers 预取

getStaticProps
getServerSideProps
中的查询。

因此推荐的解决方案是使用服务器端助手,可以在

getServerSideProps
函数中完成(示例来自官方文档 https://trpc.io/docs/client/nextjs/server-side-helpers#nextjs-示例):

import { createServerSideHelpers } from '@trpc/react-query/server';
import { GetServerSidePropsContext, InferGetServerSidePropsType } from 'next';
import { appRouter } from 'server/routers/_app';
import superjson from 'superjson';
import { trpc } from 'utils/trpc';

export async function getServerSideProps(
  context: GetServerSidePropsContext<{ id: string }>,
) {
  const helpers = createServerSideHelpers({
    router: appRouter,
    ctx: {},
    transformer: superjson,
  });
  const id = context.params?.id as string;

  /*
   * Prefetching the `post.byId` query.
   * `prefetch` does not return the result and never throws - if you need that behavior, use `fetch` instead.
   */
  await helpers.post.byId.prefetch({ id });

  // Make sure to return { props: { trpcState: helpers.dehydrate() } }
  return {
    props: {
      trpcState: helpers.dehydrate(),
      id,
    },
  };
}

export default function PostViewPage(
  props: InferGetServerSidePropsType<typeof getServerSideProps>,
) {
  const { id } = props;
  const postQuery = trpc.post.byId.useQuery({ id });

  if (postQuery.status !== 'success') {
    // won't happen since the query has been prefetched
    return <>Loading...</>;
  }

  const { data } = postQuery;

  return (
    <>
      <h1>{data.title}</h1>
      <em>Created {data.createdAt.toLocaleDateString()}</em>
      <p>{data.text}</p>
      <h2>Raw data:</h2>
      <pre>{JSON.stringify(data, null, 4)}</pre>
    </>
  );
}
© www.soinside.com 2019 - 2024. All rights reserved.