【问题标题】:How can I pass params from Nextjs 12 middleware to the route handler如何将参数从 Nextjs 12 中间件传递给路由处理程序
【发布时间】:2022-10-05 13:31:27
【问题描述】:

我正在使用新的稳定 nextjs 12 中间件,并尝试将参数从这个中间件传递给路由处理程序。

我的用例:我正在使用中间件通过 json Web 令牌进行身份验证。此令牌包括例如公司 ID,我想将此公司 ID 传递给以下路由处理程序以验证用户输入。

我的代码如下所示:

export async function middleware(req: NextRequest) {
 if (request.nextUrl.pathname.startsWith("/user")) {
   let {valid, token} = (await authVerify(
     req.cookies.get("token")
   ))
   if (valid) {
     return NextResponse.next();
   }
   return NextResponse.json({ valid: false, message: "invalid token" });
 }
}

export default async function getAllUserHandler(
  req: NextApiRequest,
  res: NextApiResponse
) 
  const companyId = //req.company_id or something
  return await userQuery(companyId);
}

【问题讨论】:

  • NextApiRequest 是否也不能通过req.cookies.get("token") 访问?
  • 是的,但是我必须这样做两次,并且我必须将它包含在每个路由处理程序中。我的想法会做得更舒服。

标签: next.js middleware


【解决方案1】:

我不确定它是否有效,但我会试试这个。请参阅下面的行// Maybe this also works

export async function middleware(req: NextRequest) {
    if (request.nextUrl.pathname.startsWith("/user")) {
        const { valid, token } = await authVerify(req.cookies.get("token"));

        if (valid) {
            const response = NextResponse.next();
            // You can add cookies
            response.cookies.set('vercel', 'fast', { path: '/test' });
            // Maybe this also works
            response.company_id = token.company_id;
            return response;

        }
        return NextResponse.json({ valid: false, message: "invalid token" });
    }
}

export default async function getAllUserHandler(
    req: NextApiRequest,
    res: NextApiResponse
) {
    const companyId = req.company_id;
    return await userQuery(companyId);
}

【讨论】:

  • 一些反馈怎么样。它能为您提供帮助吗?
【解决方案2】:

我们找到了 12.2+ 中间件的解决方案 - 发布在这里:

https://clerk.dev/blog/nextjs-pass-value-from-middleware-to-api-routes-and-getserversideprops

这适用于 API 路由和 getServerSideProps

用法:中间件.js

import { NextResponse } from "next/server";
import { withContext } from "./context";

// Pre-define the possible context keys to prevent spoofing
const allowedContextKeys = ["foo"];

export default withContext(allowedContextKeys, (setContext, req) => {
  setContext("foo", "bar");
  return NextResponse.next();
});

用法:API 路由(节点)

import { getContext } from "../../context";

export default function handler(req, res) {
  res.status(200).json({ foo: getContext(req, "foo") });
}

用法:API 路由(边缘)

import { getContext } from "../../context";

export default function handler(req) {
  return new Response(JSON.stringify({ foo: getContext(req, "foo") }));
}

用法:getServerSideProps(边缘和节点)

import { getContext } from "../context";

export const getServerSideProps = ({ req }) => {
  return { props: { foo: getContext(req, "foo") } };
};

来源:(保存到根目录下的 context.js)

import { NextResponse } from "next/server";

const ctxKey = (key) => `ctx-${key.toLowerCase()}`;

export const getContext = (req, rawKey) => {
  const key = ctxKey(rawKey);

  let headerValue =
    typeof req.headers.get === "function"
      ? req.headers.get(key) // Edge
      : req.headers[key]; // Node;

  // Necessary for node in development environment
  if (!headerValue) {
    headerValue = req.socket?._httpMessage?.getHeader(key);
  }

  if (headerValue) {
    return headerValue;
  }

  // Use a dummy url because some environments only return
  // a path, not the full url
  const reqURL = new URL(req.url, "http://dummy.url");

  return reqURL.searchParams.get(key);
};

export const withContext = (allowedKeys, middleware) => {
  // Normalize allowed keys
  for (let i = 0; i < allowedKeys.length; i++) {
    if (typeof allowedKeys[i] !== "string") {
      throw new Error("All keys must be strings");
    }
    allowedKeys[i] = ctxKey(allowedKeys[i]);
  }

  return (req, evt) => {
    const reqURL = new URL(req.url);

    // First, make sure allowedKeys aren't being spoofed.
    // Reliably overriding spoofed keys is a tricky problem and
    // different hosts may behave different behavior - it's best
    // just to safelist "allowedKeys" and block if they're being
    // spoofed
    for (const allowedKey of allowedKeys) {
      if (req.headers.get(allowedKey) || reqURL.searchParams.get(allowedKey)) {
        throw new Error(
          `Key ${allowedKey.substring(
            4
          )} is being spoofed. Blocking this request.`
        );
      }
    }

    const data = {};

    const setContext = (rawKey, value) => {
      const key = ctxKey(rawKey);
      if (!allowedKeys.includes(key)) {
        throw new Error(
          `Key ${rawKey} is not allowed. Add it to withContext's first argument.`
        );
      }
      if (typeof value !== "string") {
        throw new Error(
          `Value for ${rawKey} must be a string, received ${typeof value}`
        );
      }
      data[key] = value;
    };

    let res = middleware(setContext, req, evt) || NextResponse.next();

    // setContext wasn't called, passthrough
    if (Object.keys(data).length === 0) {
      return res;
    }

    // Don't modify redirects
    if (res.headers.get("Location")) {
      return res;
    }

    const rewriteURL = new URL(
      res.headers.get("x-middleware-rewrite") || req.url
    );

    // Don't modify cross-origin rewrites
    if (reqURL.origin !== rewriteURL.origin) {
      return res;
    }

    // Set context directly on the res object (headers)
    // and on the rewrite url (query string)
    for (const key in data) {
      res.headers.set(key, data[key]);
      rewriteURL.searchParams.set(key, data[key]);
    }

    // set the updated rewrite url
    res.headers.set("x-middleware-rewrite", rewriteURL.href);

    return res;
  };
};

【讨论】:

    猜你喜欢
    • 2018-02-21
    • 1970-01-01
    • 2011-05-02
    • 1970-01-01
    • 1970-01-01
    • 2012-08-30
    • 1970-01-01
    相关资源
    最近更新 更多