Next.js - 错误:仅支持绝对网址
Posted
技术标签:
【中文标题】Next.js - 错误:仅支持绝对网址【英文标题】:Next.js - Error: only absolute urls are supported 【发布时间】:2017-11-04 15:36:00 【问题描述】:我使用 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
【问题讨论】:
【参考方案1】:如果您正在使用下一个环境配置,请在您的变量前面加上 NEXT_PUBLIC_
,如此处提到的 Exposing Environment Variables to the Browser。
【讨论】:
【参考方案2】:您可以在 dockerfile(您用来部署的工具)上的 SERVER_URL 环境变量中添加您的域名,因此它将是一个绝对路径,这就是 getServerSideProps 所需要的。
示例:
API_URL=https://deployement.com/api
【讨论】:
【参考方案3】:这听起来很傻,但值得一提。如果您在 Web 应用程序中使用 s-s-r,则 fetch 调用将使用客户端上的相对链接,但会在服务器上失败。只有服务器需要绝对链接!
如果您想阻止服务器发出请求,只需将其包装在逻辑中
if(global.window)
const req = fetch('/api/test');
...
【讨论】:
【参考方案4】:类似于@Shanker's answer,但如果您不想为此安装额外的软件包,这里是如何做到的。
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')
【讨论】:
【参考方案5】:如果您有 absolute
路径问题。尝试使用swr 访问数据。
注意:这是一个 React 钩子,所以你必须在组件内部调用。
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"
,
感谢大家的巨大贡献,我希望分享的答案也能帮助别人。
【讨论】:
【参考方案6】:如果您的项目托管在支持它的提供商上,您可以使用环境变量。
env.local
// Local
URL="http://localhost:3000"
// Production
URL="https://prod.com"
那么你就可以使用下面的了。
const URL = process.env;
const data = await fetcher(URL + '/api');
【讨论】:
【参考方案7】:fetch 方法中的 URL 似乎有问题。 对我来说,它通过更改 fetch 方法中的 url 来解决。 注意URL地址的正确性。
【讨论】:
【参考方案8】:在 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
【讨论】:
【参考方案9】:这个简单的解决方案对我有用,无需添加额外的配置文件,
安装
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);
【讨论】:
req
仅在服务器端可用,因此您需要为客户端渲染添加一些检查/处理【参考方案10】:
案例 1。这不是错误。 isomorphic-unfetch 是通过 s-s-r 模式运行的,因此 Node.js 需要知道从中获取的绝对 url,因为后端不知道您的浏览器设置。
案例2.另一个场景是防止http主机中毒headers攻击。
将密钥和令牌附加到包含它的链接:
<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 的简单实现,但可以在客户端和服务器环境中使用。
了解更多信息:
-
Isomorphic unfetch - Switches between unfetch & node-fetch for client & server
Prevent http host headers attack
Fetching Data for Pages
【讨论】:
【参考方案11】:在 nock 之后使用 .log(console.log) ,因此您将获得完全不匹配和预期的 url 。 示例:
nock("http://localhost")
.log(console.log)
.persist()
.get("/api/config")
.reply(200, data: 1234 )
【讨论】:
【参考方案12】:正如错误所述,您必须为您正在制作的 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
【讨论】:
但是当您的数据真正存储在本地时呢?我在本地有一些本地化的静态 json @PaulT:'undefined' === typeof window ? 'http://localhost:3000' : 'https://your_deployment.server.com';
以上是关于Next.js - 错误:仅支持绝对网址的主要内容,如果未能解决你的问题,请参考以下文章
尝试将 FontAwesome 放入正文时出现 Next.js 链接错误
在使用 ZEIT Now 部署的 Next.js 应用程序中使用绝对导入
直接访问网址时如何解决“无法读取未定义的属性'文档'”? Next.js 和 apexcharts 库
仅进行“静态生成”时,是不是真的需要在“Next.js + Redux Toolkit”应用程序中使用“next-redux-wrapper”?