Next.js - Error: only absolute urls are supported
Next.js - Error: only absolute urls are supported
我使用 express 作为 next.js 的自定义服务器。一切正常,当我点击产品到产品列表时
第一步:我点击产品Link
第 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
如错误所述,您必须为您正在制作的 fetch
使用绝对值 URL。我假设它与可以执行代码的不同环境(客户端和服务器)有关。在这种情况下,相对 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';
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
}
}
在 nock 之后使用 .log(console.log) ,所以你会得到完全不匹配和预期的 url 。
示例:
nock("http://localhost")
.log(console.log)
.persist()
.get("/api/config")
.reply(200, { data: 1234 })
情况一,不是错误。 isomorphic-unfetch是SSR模式运行,所以Node.js需要知道绝对url才能从中获取,因为后端不知道你的浏览器设置。
案例二,另一种场景是防止http主机中毒headers攻击
append secret keys and tokens to links containing it:
<a href="http://_SERVER['HOST']?token=topsecret"> (Django, Gallery, others)
....and even directly import scripts from it:
<script src="http://_SERVER['HOST']/misc/jquery.js?v=1.4.4">
案例 3。isomorphic-unfetch
这是我们要用来获取数据的库。它是浏览器抓取的简单实现 API,但在客户端和服务器环境中都有效。
了解更多信息:
这个简单的解决方案对我很有效,无需添加额外的配置文件,
安装
npm install --save next-absolute-url
用法
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);
}
在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
与 类似,但如果您不想为此安装额外的软件包,请按以下步骤安装。
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')
}
如果您的项目托管在支持它的提供商上,您可以使用环境变量。
env.local
// Local
URL="http://localhost:3000"
// Production
URL="https://prod.com"
那你就可以用下面的了
const { URL } = process.env;
const data = await fetcher(URL + '/api');
如果您有 absolute
路径问题。尝试使用 swr 访问数据。
注意:这是一个React hooks,所以你必须在组件内部调用。
import useSWR from 'swr';
// optionally you can use unfetch package from npm or built yours to handle promise.
const fetcher = (...args) => fetch(...args).then(res => res.json())
export const AllProducts = () => {
const { data, error } = useSWR('/api/products', fetcher)
if (error) return <div>failed to load</div>
if (!data) return <div>loading...</div>
return (
<div>{data}</div>
);
};
在生产中导出或部署
每当您尝试在 Vercel 上进行部署时,您都可能会遇到错误。例如`
warn - Statically exporting a Next.js application via `next export` disables API routes`.
这意味着您正在尝试导出数据并且NextJS
不支持从pages/api/*
目录中获取数据。为了避免错误,最好将构建和导出命令分开。
// package.json
{
"scripts": {
"dev": "next",
"build": "next build", // No next export command
"start": "next start"
},
}
感谢大家做出的巨大贡献,我希望分享的答案也能对其他人有所帮助。
这听起来很傻,但值得一提。如果您在 webapp 中使用 SSR,则 fetch 调用将在客户端上与相对 link 一起工作,但在服务器上会失败。只有服务器需要绝对link!
如果你想阻止服务器发出请求,只需将其包装在逻辑中
if(global.window){
const req = fetch('/api/test');
...
}
如果您正在使用下一个环境配置,请在变量前加上 NEXT_PUBLIC_
前缀,如此处 Exposing Environment Variables to the Browser。
把它放在那里是因为它出现在 google 中导致我的问题,即使问题本身并不真正相关(除了相同的依赖项抛出相同的错误消息,尽管出于不同的原因在不同的环境中)。
我在尝试验证 (verify:verify
) 我在 etherscan 上的合同时使用 hardhat 遇到了这个问题。问题是在 hardhat 配置中,我在 rinkeby
下没有完整的 url
(因为我在 rinkeby 上验证,将是主网等)。 Copy/pasting 一些配置内容很快进入了我从别人那里克隆的项目,他们在他们的 .env
中有一个完整的 URL,而我在配置中有 url 并且只存储我的 api 键在我的 .env
.
不过,要解决这个问题很简单——进入 node_modules
,然后找到 node-fetch
文件夹,然后是 lib
,(这是我的记忆——只需找到在你的堆栈跟踪中呕吐的行)然后是行号,然后在那里放一个控制台日志以查看你看到的“坏” url 是什么。通常这就足够了;在我的例子中,它是一个 API 键,显然不是 URL,这使得它很容易解决。
如果您在调用 fetch 函数之前在变量中声明 URL,它会在执行时不会抛出错误。
const url = "/api/products";
await fetch(url);
而不是
await fetch("/api/products");
这样您就不必在提出请求之前弄清楚主机。
我使用 express 作为 next.js 的自定义服务器。一切正常,当我点击产品到产品列表时
第一步:我点击产品Link
第 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
如错误所述,您必须为您正在制作的 fetch
使用绝对值 URL。我假设它与可以执行代码的不同环境(客户端和服务器)有关。在这种情况下,相对 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';
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
}
}
在 nock 之后使用 .log(console.log) ,所以你会得到完全不匹配和预期的 url 。 示例:
nock("http://localhost")
.log(console.log)
.persist()
.get("/api/config")
.reply(200, { data: 1234 })
情况一,不是错误。 isomorphic-unfetch是SSR模式运行,所以Node.js需要知道绝对url才能从中获取,因为后端不知道你的浏览器设置。
案例二,另一种场景是防止http主机中毒headers攻击
append secret keys and tokens to links containing it:
<a href="http://_SERVER['HOST']?token=topsecret"> (Django, Gallery, others)
....and even directly import scripts from it:
<script src="http://_SERVER['HOST']/misc/jquery.js?v=1.4.4">
案例 3。isomorphic-unfetch
这是我们要用来获取数据的库。它是浏览器抓取的简单实现 API,但在客户端和服务器环境中都有效。
了解更多信息:
这个简单的解决方案对我很有效,无需添加额外的配置文件,
安装
npm install --save next-absolute-url
用法
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);
}
在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
与
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')
}
如果您的项目托管在支持它的提供商上,您可以使用环境变量。
env.local
// Local
URL="http://localhost:3000"
// Production
URL="https://prod.com"
那你就可以用下面的了
const { URL } = process.env;
const data = await fetcher(URL + '/api');
如果您有 absolute
路径问题。尝试使用 swr 访问数据。
注意:这是一个React hooks,所以你必须在组件内部调用。
import useSWR from 'swr';
// optionally you can use unfetch package from npm or built yours to handle promise.
const fetcher = (...args) => fetch(...args).then(res => res.json())
export const AllProducts = () => {
const { data, error } = useSWR('/api/products', fetcher)
if (error) return <div>failed to load</div>
if (!data) return <div>loading...</div>
return (
<div>{data}</div>
);
};
在生产中导出或部署
每当您尝试在 Vercel 上进行部署时,您都可能会遇到错误。例如`
warn - Statically exporting a Next.js application via `next export` disables API routes`.
这意味着您正在尝试导出数据并且NextJS
不支持从pages/api/*
目录中获取数据。为了避免错误,最好将构建和导出命令分开。
// package.json
{
"scripts": {
"dev": "next",
"build": "next build", // No next export command
"start": "next start"
},
}
感谢大家做出的巨大贡献,我希望分享的答案也能对其他人有所帮助。
这听起来很傻,但值得一提。如果您在 webapp 中使用 SSR,则 fetch 调用将在客户端上与相对 link 一起工作,但在服务器上会失败。只有服务器需要绝对link!
如果你想阻止服务器发出请求,只需将其包装在逻辑中
if(global.window){
const req = fetch('/api/test');
...
}
如果您正在使用下一个环境配置,请在变量前加上 NEXT_PUBLIC_
前缀,如此处 Exposing Environment Variables to the Browser。
把它放在那里是因为它出现在 google 中导致我的问题,即使问题本身并不真正相关(除了相同的依赖项抛出相同的错误消息,尽管出于不同的原因在不同的环境中)。
我在尝试验证 (verify:verify
) 我在 etherscan 上的合同时使用 hardhat 遇到了这个问题。问题是在 hardhat 配置中,我在 rinkeby
下没有完整的 url
(因为我在 rinkeby 上验证,将是主网等)。 Copy/pasting 一些配置内容很快进入了我从别人那里克隆的项目,他们在他们的 .env
中有一个完整的 URL,而我在配置中有 url 并且只存储我的 api 键在我的 .env
.
不过,要解决这个问题很简单——进入 node_modules
,然后找到 node-fetch
文件夹,然后是 lib
,(这是我的记忆——只需找到在你的堆栈跟踪中呕吐的行)然后是行号,然后在那里放一个控制台日志以查看你看到的“坏” url 是什么。通常这就足够了;在我的例子中,它是一个 API 键,显然不是 URL,这使得它很容易解决。
如果您在调用 fetch 函数之前在变量中声明 URL,它会在执行时不会抛出错误。
const url = "/api/products";
await fetch(url);
而不是
await fetch("/api/products");
这样您就不必在提出请求之前弄清楚主机。