Next.js - 错误:仅支持绝对网址

IT技术 reactjs react-redux next.js
2021-03-28 04:20:39

我使用 express 作为我的 next.js 自定义服务器。一切都很好,当我点击产品到产品列表时

第 1 步:我点击产品链接

在此处输入图片说明

第 2 步:它将显示数据库中的产品。

在此处输入图片说明

但是,如果我刷新/products页面,则会收到此错误

在此处输入图片说明

服务器代码(查看/products端点)

app.prepare()
.then(() => {
  const server = express()

  // This is the endpoints for products
  server.get('/api/products', (req, res, next) => {
    // Im using Mongoose to return the data from the database
    Product.find({}, (err, products) => {
      res.send(products)
    })
  })

  server.get('*', (req, res) => {
    return handle(req, res)
  })

  server.listen(3000, (err) => {
    if (err) throw err
    console.log('> Ready on http://localhost:3000')
  })
})
.catch((ex) => {
  console.error(ex.stack)
  process.exit(1)
})

页面 - products.js(将循环产品 json 数据的简单布局)

import Layout from '../components/MyLayout.js'
import Link from 'next/link'
import fetch from 'isomorphic-unfetch'

const Products = (props) => (
  <Layout>
    <h1>List of Products</h1>
    <ul>
      { props.products.map((product) => (
        <li key={product._id}>{ product.title }</li>
      ))}
    </ul>
  </Layout>
)

Products.getInitialProps = async function() {

  const res = await fetch('/api/products')
  const data = await res.json()

  console.log(data)
  console.log(`Showed data fetched. Count ${data.length}`)

  return {
    products: data
  }
}

export default Products
6个回答

正如错误所述,您必须使用绝对 URL 作为fetch您正在制作的内容。我假设它与可以执行代码的不同环境(客户端和服务器)有关。在这种情况下,相对 URL 不够明确和可靠。

解决此问题的一种方法是将服务器地址硬编码到您的fetch请求中,另一种方法是设置一个config对您的环境做出reactmodule:

/config/index.js

const dev = process.env.NODE_ENV !== 'production';

export const server = dev ? 'http://localhost:3000' : 'https://your_deployment.server.com';

产品.js

import { server } from '../config';

// ...

Products.getInitialProps = async function() {

  const res = await fetch(`${server}/api/products`)
  const data = await res.json()

  console.log(data)
  console.log(`Showed data fetched. Count ${data.length}`)

  return {
    products: data
  }
}
但是当您的数据真正存储在本地时呢?我在本地有一些本地化的静态 json
2021-06-01 04:20:39
@保罗: 'undefined' === typeof window ? 'http://localhost:3000' : 'https://your_deployment.server.com';
2021-06-12 04:20:39

@Shanker 的回答类似,但如果您不想为此安装附加软件包,请按以下步骤操作。

async getInitialProps({ req }) {
    const protocol = req.headers['x-forwarded-proto'] || 'http'
    const baseUrl = req ? `${protocol}://${req.headers.host}` : ''

    const res = await fetch(baseUrl + '/api/products')
}

案例 1. 这不是错误。isomorphic-unfetch 是通过 SSR 模式运行的,所以 Node.js 需要知道绝对 url 才能从中获取,因为后端不知道您的浏览器设置。

案例2.另一种场景是防止http主机中毒头攻击。

将密钥和令牌附加到包含它的链接:

<a href="http://_SERVER['HOST']?token=topsecret">  (Django, Gallery, others)

....甚至直接从中导入脚本:

<script src="http://_SERVER['HOST']/misc/jquery.js?v=1.4.4">

案例 3.isomorphic-unfetch它是我们将用来获取数据的库。它是浏览器获取 API 的简单实现,但在客户端和服务器环境中均可使用。

阅读更多相关信息:

  1. 同构 unfetch - 在客户端和服务器的 unfetch 和 node-fetch 之间切换
  2. 防止http主机头攻击
  3. 获取页面数据

在 NextJS 9.5 中,我们也可以使用process.cwd().
process.cwd() 将为您提供执行 Next.js 的目录。

import path from 'path'
import fs from "fs";

export const getStaticProps: GetStaticProps = async () => {
    const dataFilePath = path.join(process.cwd(), "jsonFiles", "data.json");
    console.log(dataFilePath);     // will be YourProject/jsonFiles/data.json

    const fileContents = fs.readFileSync(dataFilePath, "utf8");
    const data: TypeOfData[] = JSON.parse(fileContents);
    return { props: { data } };
};

参考:https : //nextjs.org/docs/basic-features/data-fetching#reading-files-use-processcwd

如果您的项目托管在支持它的提供程序上,您可以使用环境变量。

环境.local

// Local
URL="http://localhost:3000"

// Production
URL="https://prod.com"

然后您可以使用以下内容。

const { URL } = process.env;
const data = await fetcher(URL + '/api');