Различные типы контента на одном маршруте с Serverless Next JS - PullRequest
0 голосов
/ 10 июля 2020

Мне интересно, возможен ли следующий сценарий с бессерверным (развернутым на Vercel) Next JS:

У меня есть маршрут /product/[id].tsx, когда вы отправляете запрос с заголовком Accept: text/html, Я бы хотел, чтобы go проходил через обычный поток Next JS со страницей React. Но когда запрос передается с Accept: application/json, я хотел бы, чтобы он возвращал представление JSON.

Я выполнил это с помощью некоторого специального промежуточного программного обеспечения, которое я написал для Express (см. Ниже), но я также хотел бы развернуть его на Vercel, а Vercel не предназначен для работы с пользовательской реализацией Express.

Итак, вопрос в том, можно ли это сделать в бессерверной среде? Может ли одна из страниц Next JS React возвращать чистый JSON, или вы можете вернуть React из маршрута Next JS Api? Или есть другой способ выполнить sh это?

server.ts

import express, { Request, Response } from "express";
import next from 'next'
import { parse } from 'url'

const port = parseInt(process.env.PORT || "3000", 10);
const dev = process.env.NODE_ENV !== "production";

async function run(): Promise<void> {
  const app = express();
  const nextApp = next({ dev })
  const nextHandler = nextApp.getRequestHandler()
  await nextApp.prepare()

  app.use((req, res) => {
    res.format({
      "text/html": async (req, res) => {
        const parsedUrl = parse(req.url!, true)
        await this.handler(req, res, parsedUrl)
      },
      "application/json": async (req, res) => {
        res.json({
          "dummy": "data"
        })
      }
    })
  });

  app.listen(port, () => {
    console.log(
      `> Server listening at http://localhost:${port} as ${
        dev ? "development" : process.env.NODE_ENV
      }`
    );
  });
}

run()

1 Ответ

0 голосов
/ 11 июля 2020

Благодаря @timneutkens (ведущему инженеру Next JS) в Twitter у нас есть ответ. Это возможно. Вы используете getServerSideProps и выполняете все, что хотите, с объектом res. Только не забудьте закончить его .end, чтобы он пропустил этап рендеринга.

Я сделал образец репозитория для кода здесь: https://github.com/jaxoncreed/nextjs-content-type-test

А вот важная страница:

import Head from 'next/head'

export default function Home() {
  return (
    <div className="container">
      <Head>
        <title>Create Next App</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main>
        <h1>Test App</h1>
      </main>

      
    </div>
  )
}

export async function getServerSideProps({ req, res }) {
  if (req.headers.accept === "application/json") {
    res.setHeader('Content-Type', 'application/json')
    res.write(JSON.stringify({ "dummy": "data" }))
    res.end()
  }
  return {
    props: {}, // will be passed to the page component as props
  }
}
...