Next.js API 在出现错误或没有 HTTP 方法匹配时路由默认响应

phw*_*hwt 7 javascript node.js express next.js

我正在 Next.js 中处理API 路由,每个路径的结构如下:

import { NextApiRequest, NextApiResponse } from "next";

export default async (req: NextApiRequest, res: NextApiResponse) => {
  const { query } = req;

  try {
    switch (req.method) {
      case "GET":
        // Do some GET stuff
        res.status(200).send(result);
        break;

      case "POST":
        // Do some POST stuff
        res.status(200).send(result);
        break;

      default:
        // No Matched Method
        res.status(405).send("Method Not Allowed");
        break;
    }
  } catch (e) {
    // Unprocessable Entity
    res.status(422).send(e);
  }
};
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,default案例和catch零件将在所有文件中重复。所以,我想知道:

  • 当没有匹配的方法或处理请求时出现错误时,Next.js 是否有内置支持默认响应?
  • (如果没有内置支持)怎么办?

如果没有内置支持,这是我的解决方案:

  • 使用中间件
  • 创建一个函数来包装之前的 API 调用export default。我尝试实现这一点,但停留在访问reqres对象上,如下面的代码块所示。
const wrapAPICall = async (
  fn: (req: NextApiRequest, res: NextApiResponse) => void
) => {
  try {
    await fn(req, res); // Can't access req, res here
  } catch (e) {
    res.status(422).send(e); // Also can't access req, res here
  } finally {
    if (!res.headersSent) res.status(405).send("Method Not Allowed");
  }
};

const apiCall = async (req: NextApiRequest, res: NextApiResponse) => {
  // Does some API stuff
};

export default wrapAPICall(apiCall);
Run Code Online (Sandbox Code Playgroud)

phw*_*hwt 7

我找到了另一种解决方案,而不是编写自定义包装器,而是使用next-connectNext.js 的路由中间件

下面的代码产生与包装器解决方案相同的结果。

import { NextApiRequest, NextApiResponse } from "next";
import nc from "next-connect";

// Handle Error Here
const handler = nc({
  onError: (err, req: NextApiRequest, res: NextApiResponse) => {
    res.status(500).end(err.toString());
  },
  onNoMatch: (req: NextApiRequest, res: NextApiResponse) => {
    res.status(405).send("Method Not Allowed");
  },
});

handler
  .get(async (req: NextApiRequest, res: NextApiResponse) => {
    // Do some GET stuff
    res.status(200).json(...);
  })
  .post(async (req: NextApiRequest, res: NextApiResponse) => {
    // Do some POST stuff
    res.status(200).json(...);
  });

export default handler;
Run Code Online (Sandbox Code Playgroud)

Next.js 将 API 路由分离到许多文件中,如果您希望处理程序可重用,请这样做。

/modules/Utils.ts

export const apiHandler = {
  onError: (err, req: NextApiRequest, res: NextApiResponse) => {
    res.status(500).end(err.toString());
  },
  onNoMatch: (req: NextApiRequest, res: NextApiResponse) => {
    res.status(405).send("Method Not Allowed");
  },
};
Run Code Online (Sandbox Code Playgroud)

/pages/api/index.ts

import nc from "next-connect";
import { apiHandler } from "../modules/Utils";

const handler = nc(apiHandler); // Use handler exported from Utils

handler
  .get((req, res) => {...})
  .post((req, res) => {...});

export default handler;
Run Code Online (Sandbox Code Playgroud)


jul*_*ves 4

我认为你的包装解决方案是合理的。要使其工作,您只需从包装器返回一个函数即可。

const wrapAPICall = (
    fn: (req: NextApiRequest, res: NextApiResponse) => void
) => {
    return async (req: NextApiRequest, res: NextApiResponse) => {
        try {
            await fn(req, res);
        } catch (e) {
            res.status(422).send(e);
        } finally {
            if (!res.headersSent) res.status(405).send("Method Not Allowed");
        }
    }
};
Run Code Online (Sandbox Code Playgroud)