最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Different Content-Types on the same route with Serverless Next JS - Stack Overflow

programmeradmin7浏览0评论

I'm wondering if the following scenario is possible with serverless (deployed on Vercel) Next JS:

I have a route /product/[id].tsx when you send a request with the header Accept: text/html, I would like it to go through the normal Next JS flow with a React page. But, when a request is given with Accept: application/json, I would like it to return the JSON representation.

I have acplished it by using some custom middleware I wrote for Express (see below), but I would also like to deploy it on Vercel, and Vercel is not designed to work with a custom Express implementation.

So the question is, is it possible to do this in a serverless environment? Could one of the Next JS React pages return pure JSON, or could you return React from a Next JS Api route? Or is there another way to acplish this?

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()

I'm wondering if the following scenario is possible with serverless (deployed on Vercel) Next JS:

I have a route /product/[id].tsx when you send a request with the header Accept: text/html, I would like it to go through the normal Next JS flow with a React page. But, when a request is given with Accept: application/json, I would like it to return the JSON representation.

I have acplished it by using some custom middleware I wrote for Express (see below), but I would also like to deploy it on Vercel, and Vercel is not designed to work with a custom Express implementation.

So the question is, is it possible to do this in a serverless environment? Could one of the Next JS React pages return pure JSON, or could you return React from a Next JS Api route? Or is there another way to acplish this?

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()
Share Improve this question asked Jul 10, 2020 at 18:20 jaxoncreedjaxoncreed 1,1282 gold badges14 silver badges25 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 8

Thanks to @timneutkens (Lead engineer for NextJS) on Twitter we have our answer. It is possible. You use getServerSideProps and perform everything you want to the res object there. Just be sure to end it with .end so it skips the react rendering phase.

I've made a sample repo for the code here: https://github./jaxoncreed/nextjs-content-type-test

And here's the page that matters:

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 ponent as props
  }
}
发布评论

评论列表(0)

  1. 暂无评论