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

sin*_*Gob 4 reactjs react-redux next.js

我正在使用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)
})
Run Code Online (Sandbox Code Playgroud)

Pages - 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
Run Code Online (Sandbox Code Playgroud)

bub*_*ser 22

与@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')
}
Run Code Online (Sandbox Code Playgroud)

  • 依赖 HOST 标头安全吗?标头由客户端发送,可以是任何内容。如果恶意代码在 HOST 中发送其服务器地址,他们就可以在您的代码中获取他们想要的任何数据。当然,这取决于您稍后如何处理这些数据,但我确实相信它打开了最好保持关闭的大门。 (3认同)
  • 是的,依赖标头绝对不安全,因为它可以被中间人攻击改变。 (2认同)

Fab*_*ltz 16

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

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

/config/index.js

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

export const server = dev ? 'http://localhost:3000' : 'https://your_deployment.server.com';
Run Code Online (Sandbox Code Playgroud)

products.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
  }
}
Run Code Online (Sandbox Code Playgroud)

  • @PaulT:“未定义”=== typeof 窗口?'http://localhost:3000' : 'https://your_deployment.server.com';` (3认同)

sid*_*son 13

这听起来很愚蠢,但值得一提。如果您在 Web 应用程序中使用 SSR,则 fetch 调用将在客户端上使用相对链接,但在服务器上将失败。只有服务器需要绝对链接!

如果你想阻止服务器发出请求,只需将其包装在逻辑中

if(global.window){
   const req = fetch('/api/test');
   ...
}
Run Code Online (Sandbox Code Playgroud)


Sha*_*man 6

这个简单的解决方案对我有用,无需添加额外的配置文件,

安装

npm install --save next-absolute-url
Run Code Online (Sandbox Code Playgroud)

用法

import absoluteUrl from "next-absolute-url";

async getInitialProps({ req }){
  const { origin } = absoluteUrl(req, req.headers.host);
  console.log('Requested URL ->',origin); 
  // (or) other way
  const host = absoluteUrl(req, req.headers.host);
  console.log('Requested URL ->',host.origin); 
}
Run Code Online (Sandbox Code Playgroud)

  • `req` 仅在服务器端可用,因此您需要为客户端渲染添加一些检查/处理 (3认同)

小智 5

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

本地环境

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

// Production
URL="https://prod.com"
Run Code Online (Sandbox Code Playgroud)

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

const { URL } = process.env;
const data = await fetcher(URL + '/api');
Run Code Online (Sandbox Code Playgroud)

  • 你真的能解构 process.env 吗? (2认同)