简体   繁体   中英

Fetch error when building Next.js static website in production

I don't understand these errors when I export as production npm run build , but when I test npm run dev it works just fine. I use getStaticProps and getStaticPath fetch from an API route.

First when I npm run build

FetchError: invalid json response body at https://main-website-next.vercel.app/api/products reason: Unexpected token T in JSON at position
0
    at D:\zummon\Main Website\main-website-next\node_modules\node-fetch\lib\index.js:272:32
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
    at async getStaticPaths (D:\zummon\Main Website\main-website-next\.next\server\pages\product\[slug].js:1324:18)
    at async buildStaticPaths (D:\zummon\Main Website\main-website-next\node_modules\next\dist\build\utils.js:16:80)
    at async D:\zummon\Main Website\main-website-next\node_modules\next\dist\build\utils.js:26:612
    at async D:\zummon\Main Website\main-website-next\node_modules\next\dist\build\tracer.js:1:1441 {
  type: 'invalid-json'
}

\pages\product\[slug]

import { assetPrefix } from '../../next.config'

export default function Page(){...}

export const getStaticProps = async ({ params: { slug }, locale }) => {
  const res = await fetch(`${assetPrefix}/api/products/${slug}`)
  const result = await res.json()
  const data = result.filter(item => item.locale === locale)[0]
  const { title, keywords, description } = data
  return {
    props: {
      data,
      description,
      keywords, 
      title
    }
  }
}

export const getStaticPaths = async () => {
  const res = await fetch(`${assetPrefix}/api/products`)
  const result = await res.json()
  const paths = result.map(({ slug, locale }) => ({ params: { slug: slug }, locale }))
  return {
    fallback: true,
    paths,
  }
}

next.config.js

const isProd = process.env.NODE_ENV === 'production'

module.exports = {
  assetPrefix: isProd ? 'https://main-website-next.vercel.app' : 'http://localhost:3000',
  i18n: {
    localeDetection: false,
    locales: ['en', 'th'],
    defaultLocale: 'en',
  }
}

API routes

// pages/api/products/index.js
import data from '../../../data/products'
export default (req, res) => {
  res.status(200).json(data)
}

// pages/api/products/[slug].js
import db from '../../../data/products'
export default ({ query: { slug } }, res) => {
  const data = db.filter(item => item.slug === slug)
  if (data.length > 0) {
    res.status(200).json(data)
  } else {
    res.status(404).json({ message: `${slug} not found` })
  }
}

// ../../../data/products (data source)
module.exports = [
  { locale: "en", slug: "google-sheets-combine-your-cashflow",
    title: "Combine your cashflow",
    keywords: ["Google Sheets","accounting"],
    description: "...",
  },
    ...
]

Second when I remove the production domain, I run npm run build but still get the error like

TypeError: Only absolute URLs are supported
    at getNodeRequestOptions (D:\zummon\Main Website\main-website-next\node_modules\node-fetch\lib\index.js:1305:9)
    at D:\zummon\Main Website\main-website-next\node_modules\node-fetch\lib\index.js:1410:19
    at new Promise (<anonymous>)
    at fetch (D:\zummon\Main Website\main-website-next\node_modules\node-fetch\lib\index.js:1407:9)
    at getStaticPaths (D:\zummon\Main Website\main-website-next\.next\server\pages\[slug].js:938:21)
    at buildStaticPaths (D:\zummon\Main Website\main-website-next\node_modules\next\dist\build\utils.js:16:86)
    at D:\zummon\Main Website\main-website-next\node_modules\next\dist\build\utils.js:26:618
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
    at async D:\zummon\Main Website\main-website-next\node_modules\next\dist\build\tracer.js:1:1441 {
  type: 'TypeError'
}

My next.config.js after remove

const isProd = process.env.NODE_ENV === 'production'

module.exports = {      //remove
  assetPrefix: isProd ? '' : 'http://localhost:3000',
  i18n: {
    localeDetection: false,
    locales: ['en', 'th'],
    defaultLocale: 'en',
  }
}

My package.json when I npm run build script

{
  "name": "main-website-next",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build && next export",
    "start": "next start"
  },
  "dependencies": {
    "next": "10.0.6",
    "react": "17.0.1",
    "react-dom": "17.0.1"
  }
}

You should not call an internal API route inside getStaticProps . Instead, you can safely use your API logic directly in getStaticProps / getStaticPaths . These only happen server-side so you can write server-side code directly .

As getStaticProps runs only on the server-side, it will never run on the client-side. It won't even be included in the JS bundle for the browser, so you can write direct database queries without them being sent to browsers.

This means that instead of fetching an API route from getStaticProps (that itself fetches data from an external source), you can write the server-side code directly in getStaticProps .

Furthermore, your API routes are not available during build-time, as the server has not been started at that point.


Here's a small refactor of your code to address the issue.

// /pages/product/[slug]

import db from '../../../data/products'

// Remaining code..

export const getStaticProps = async ({ params: { slug }, locale }) => {
    const result = db.filter(item => item.slug === slug)
    const data = result.filter(item => item.locale === locale)[0]
    const { title, keywords, description } = data
    return {
        props: {
            data,
            description,
            keywords, 
            title
        }
    }
}

export const getStaticPaths = async () => {
    const paths = db.map(({ slug, locale }) => ({ params: { slug: slug }, locale }))
    return {
        fallback: true,
        paths,
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM