You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NextJS中基于Medium API配置动态路由遇阻,求正确配置方案

解决Next.js动态路由[...slug].js配置问题

问题背景

我在Next.js应用中配置动态路由时遇到了问题。我用非官方Medium API展示Medium上的文章,首页已经能展示文章卡片列表,现在想让每张卡片通过Medium的URL路径跳转到应用内对应的页面。

API返回的Medium文章URL是转义后的完整地址,示例:"url":"https:\/\/medium.com\/@myprofile\/some-post-title-81afcccca8a7"。我截取了域名后的路径部分,用来作为Next应用的动态路由。我在post目录下创建了[...slug].js页面,但点击首页卡片跳转到mywebsite.com/post/some-post-title-81afcccca8a7时出现错误,不知道怎么正确配置这个页面。

首页获取文章的getStaticProps代码如下(API要求带密钥和主机头,返回数据需要解析):

const res = await fetch(url, options).catch((e) => {
    console.error('Error fetching data', e)
    return {
      props: { error: true }, // 作为props传给页面组件
    }
  })

  const data = await res.json()
  var article_ids = data.associated_articles

  var articleDataArr = []

  for (const article_id of article_ids) {
    let article = await fetch(
      `https://medium2.p.rapidapi.com/article/${article_id}`,
      options,
    )
    const articleData = await article.text()
    articleDataArr.push(articleData)

  }

  return {
    props: {
      articleDataArr,
    } 

解决方案

要让[...slug].js正常工作,你需要完成静态路径生成和根据slug获取对应文章数据两个核心步骤,同时还要处理slug与文章ID的映射关系:

1. 首页数据处理:保存slug与文章ID的映射

首先修改首页的getStaticProps,提取每个文章的slug并和对应的ID绑定,这样动态页面才能通过slug找到对应的文章ID:

const res = await fetch(url, options).catch((e) => {
  console.error('Error fetching data', e)
  return { props: { error: true } }
})

const data = await res.json()
const article_ids = data.associated_articles

// 存储slug和文章ID的映射,同时保留文章基础数据
const articleDataArr = []
const slugToIdMap = {}

for (const article_id of article_ids) {
  let articleRes = await fetch(
    `https://medium2.p.rapidapi.com/article/${article_id}`,
    options,
  )
  // 改用json()解析数据,方便后续处理
  const articleData = await articleRes.json()
  // 处理转义URL,提取slug
  const decodedUrl = decodeURIComponent(articleData.url)
  const path = new URL(decodedUrl).pathname
  // 截取@profile后的路径作为slug,可根据需求调整规则
  const slug = path.split('/').filter(Boolean).slice(1).join('/')
  
  articleDataArr.push({ ...articleData, slug })
  slugToIdMap[slug] = article_id
}

return {
  props: {
    articleDataArr,
    slugToIdMap,
  },
  revalidate: 86400, // 可选:开启增量静态再生,每天更新一次
}

同时,首页的文章卡片跳转链接要改为:

// 假设每个article是articleDataArr里的项
<Link href={`/post/${article.slug}`} passHref>
  <a>文章卡片</a>
</Link>

2. 配置[...slug].js的getStaticPaths

这个函数需要告诉Next.js预渲染哪些动态路径:

export async function getStaticPaths() {
  const options = {
    method: 'GET',
    headers: {
      'X-RapidAPI-Key': '你的API密钥',
      'X-RapidAPI-Host': 'medium2.p.rapidapi.com'
    }
  }
  const res = await fetch('你的文章列表API地址', options)
  const data = await res.json()
  const article_ids = data.associated_articles

  const paths = []
  for (const article_id of article_ids) {
    const articleRes = await fetch(`https://medium2.p.rapidapi.com/article/${article_id}`, options)
    const articleData = await articleRes.json()
    const decodedUrl = decodeURIComponent(articleData.url)
    const path = new URL(decodedUrl).pathname
    const slug = path.split('/').filter(Boolean).slice(1).join('/')
    
    paths.push({ params: { slug: [slug] } }) // [...slug]对应数组格式的参数
  }

  return {
    paths,
    fallback: 'blocking', // 可选:新文章自动生成静态页面,避免404
  }
}

3. 配置[...slug].js的getStaticProps

根据传入的slug参数,找到对应的文章ID并请求详情:

export async function getStaticProps({ params }) {
  const { slug } = params
  const targetSlug = slug[0] // [...slug]会把路径转为数组,取第一个元素即可

  const options = {
    method: 'GET',
    headers: {
      'X-RapidAPI-Key': '你的API密钥',
      'X-RapidAPI-Host': 'medium2.p.rapidapi.com'
    }
  }

  // 获取文章列表,匹配slug对应的ID
  const res = await fetch('你的文章列表API地址', options)
  const data = await res.json()
  const article_ids = data.associated_articles

  let articleData = null
  for (const article_id of article_ids) {
    const articleRes = await fetch(`https://medium2.p.rapidapi.com/article/${article_id}`, options)
    const tempArticle = await articleRes.json()
    const decodedUrl = decodeURIComponent(tempArticle.url)
    const path = new URL(decodedUrl).pathname
    const tempSlug = path.split('/').filter(Boolean).slice(1).join('/')
    
    if (tempSlug === targetSlug) {
      articleData = tempArticle
      break
    }
  }

  if (!articleData) {
    return { notFound: true } // 找不到文章返回404
  }

  return {
    props: { articleData },
    revalidate: 86400, // 可选:增量更新页面
  }
}

4. [...slug].js的页面组件

编写页面组件渲染文章内容:

export default function PostPage({ articleData }) {
  if (!articleData) {
    return <div>文章不存在</div>
  }

  return (
    <div className="post-container">
      <h1>{articleData.title}</h1>
      {/* 渲染文章内容,注意处理API返回的HTML格式 */}
      <div dangerouslySetInnerHTML={{ __html: articleData.content }} />
    </div>
  )
}

关键注意点

  • 确保API请求头包含正确的密钥和主机信息,避免请求失败。
  • 若文章数量较多,建议将slug与ID的映射缓存到本地文件或数据库,减少重复API请求。
  • fallback: 'blocking'可让新发布的文章自动生成静态页面,无需重新部署应用。
  • 必须先对API返回的转义URL解码,再进行路径截取操作。

内容的提问来源于stack exchange,提问作者i-am-niall

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 12:15:42