Next.js: 合法页面链接中的尾部斜杠适用于客户端导航,但会导致未找到包和硬刷新时出现 404 (ssr)

创建于 2018-09-20  ·  119评论  ·  资料来源: vercel/next.js

合法页面链接中的尾部斜杠适用于客户端导航,但会导致未找到包和硬刷新时出现 404 (ssr)

错误报告

描述错误

如果标题需要进一步说明,请告诉我。

所有相关问题都已关闭,理由是它已在 6-canary 中修复(我认为不是)或通过改进服务(这可能仅在生产静态导出中才是正确的)。

我正在将我现有的博客重写为 next.js,并且我以前使用过尾部斜杠。 一旦我建立了我的 next.js 支持的博客,最新的serve可以帮助它。 但是为了修复 dev env,我需要去掉尾部斜杠并在 prod 中使用301 Moved Permanently ; 或者在开发中使用损坏的尾部斜杠支持。

再现

这是最小的可重现案例(repro repo 的链接在代码段下方):

// pages/index.js
import Link from "next/link";

export default () => (
  <Link href="/about/">
    <a>About</a>
  </Link>
);

// pages/index.js
export default () => "about";

最小的可重现仓库https://github.com/iamstarkov/next.js-trailing-slash-bug-demo

  1. 克隆回购git clone https://github.com/iamstarkov/next.js-trailing-slash-bug-demo
  2. 更改目录cd next.js-trailing-slash-bug-demo
  3. 安装 deps yarn
  4. 运行开发: yarn dev
  5. 打开http://localhost :3000/
  6. 打开 devtools 的网络选项卡
  7. 观察http://localhost:3000/_next/static/development/pages/about.js被 200ed
  8. 观察http://localhost:3000/_next/on-demand-entries-ping?page=/about/是 200ed
  9. 观察http://localhost:3000/about/被 404ed
  10. 观察解决http://localhost:3000/about/持续尝试
  11. 在终端Client pings, but there's no entry for page: /about/观察
  12. 刷新页面
  13. 观察404页面。
  14. 删除 url 中的尾部斜杠或单击http://localhost :3000/about
  15. 观察页面被 200ed
  16. 为确保错误持久性,重复步骤 5-15 一次。

预期行为

  1. /about/不应解析为404 not found
  2. /about/应解析为200 ok
  3. 服务器不应打印Client pings, but there's no entry for page: /about/
  4. /about/about/应该以相同的方式工作

截图

不适用

系统信息

  • 操作系统:macOS High Sierra 10.13.6 (17G65)
  • 浏览器(应该无关紧要,但可以在 chrome 69.0.3497.100 和 safari Version 12.0 (13606.2.11) 中重现(与 safari 11 相同)
  • Next.js 版本:7.0.0(可以在 5.x 和 6.x 上重现)

附加上下文

在此处添加有关该问题的任何其他上下文。

如果您在https://github.com/zeit/next.js/blob/459c1c13d054b37442126889077b7056269eeb35/server/on-demand-entry-handler.js#L242 -L249 中更改此代码

node_modules/next/dist/server/on-demand-entry-handler.js本地

          const { query } = parse(req.url, true)
          const page = normalizePage(query.page)
+         console.log('query.page', query.page);
+         console.log('page', page);
+         console.log('Object.keys(entries)', Object.keys(entries));
          const entryInfo = entries[page]

          // If there's no entry.
          // Then it seems like an weird issue.
          if (!entryInfo) {
            const message = `Client pings, but there's no entry for page: ${page}`

并重新启动next dev并打开http://localhost :3000/ 并单击 about 链接然后:

  • /about
    query.page /about page /about Object.keys(entries) [ '/', '/about' ]
  • 对于/about/
    query.page /about/ page /about/ Object.keys(entries) [ '/', '/about' ] Client pings, but there's no entry for page: /about/

我认为问题(至少是部分问题)在于如果页面有斜杠,onDemandEntryHandler 的中间件无法在条目中查找页面。

我希望我 2 小时的调查和准备可以帮助解决这个问题。

story 8 feature request

最有用的评论

我们即将推出一个功能来解决这个问题——一天左右!

所有119条评论

最相关和值得注意的问题是 #1189 和 #3876

期待最终解决! @timneutkens Next 7 的尾随斜线问题的状态是什么?

@NathanielHill我可以在next@7上重现它

我正在使用 nextjs 7 并且尾部斜杠在 dev 和 prod 上为我生成一个 404:

  • 在初始页面加载时
  • 在页面刷新

并影响:

  • 一个外部链接
  • 一个内部链接
  • URL粘贴到浏览器中

只需删除尾部斜杠即可解决问题。

尾随斜杠通常由浏览器、服务器和/或其他可能粘贴链接的服务添加,因此虽然我可以控制内部链接,但很难控制外部用户可能访问的链接

我也在版本 7 中看到了这个问题。不确定这是否相关,但是,我将一个 Next.js 项目别名到另一个 Now 部署的子文件夹。 所以我们的基本 url 是primer.style并且我们将primer-components.now.sh Next.js 应用程序别名为primer.style/components 。 在生产中, primer.style/components的索引页工作正常,但primer.style/components/会产生 404。

我不得不四处搜索才能找到这个问题。 我在Netlify上使用静态部署,所以这不是 prod 的问题,但在开发(Next 7)中,如果有斜杠,编译就会冻结,而且很难弄清楚原因。 我不认为这(不处理开发环境中的斜杠)是一个好的 DX。

我也有这个问题,真的很烦人,希望尽快解决。

如果你想要尾随斜杠,你可以这样做。 <Link href='/about' as='/about/'><a>about</a></Link>但如果您使用星期五/下一条路线,这是不可能的。 所以我有一个叉子,你可以在其中添加trailingSlash作为道具。 希望这可以帮助

如果你想要尾随斜杠,你可以这样做。 <Link href='/about' as='/about/'><a>about</a></Link>但如果您使用星期五/下一条路线,这是不可能的。 所以我有一个叉子,你可以在其中添加trailingSlash作为道具。 希望这可以帮助

@aluminick对不起,我刚试过这个,但对我不起作用。 我仍然可以访问 traling-slashed 页面(最新版本),刷新后未找到(当前行为)。

#6664 和 #6752 也没有帮助,因为experimental.exportTrailingSlash没有帮助,因为它仅适用于next export ,我相信

不幸的是, @Janpot提出了一个有希望的拉取请求 #6421,但没有达成任何共识

@iamstarkov这个问题的状态是什么? server.js钩子旁边的任何解决方案?

@dryleaf状态:它仍然打开

类似的问题...添加多个正斜杠时重定向。 示例: https :

GitHub 网址无关紧要

@iamstarkov不确定你的意思。 但是在重读我原来的帖子后,看起来我本来可以更清楚。

GitHub url 旨在简单演示当使用 Next.js 构建应用程序时 url 应该(最好)如何工作。 换句话说,如果用户添加了额外的斜杠,url 应该仍然有效。

nextjs 9 有什么更新吗?

我是 Next 的新手,但是你们针对这个问题使用的解决方法是什么?

@iamstarkov这个问题的状态是什么?

我很震惊这个问题大约一年没有以任何方式解决!
Next.js 团队是否需要任何其他理由来开始解决这个问题?

无论尾部斜杠如何,URL 都应该有效。 检查网络上的任何站点。

如果这超出了 Next.js 的范围,让我们能够在 Now 中配置它。
我真的很困惑 Zeit 团队多年来一直忽视这些关键问题。

@exentrich这很容易在 Zeit Now 中配置,只需 301 将所有尾部斜杠重定向到没有斜杠的同一路由:

now.json

"routes": [
    {
      "src": "/(.*)/",
      "status": 301,
      "headers": { "Location": "/$1" }
    },
    ...
]

但是,我也不明白为什么 Next.js 本身没有处理这个问题,以及为什么团队忽略了这个问题。

这和public/ (正在开发中)是我看到 CRA 转换遇到的主要问题。

@rauchg

@NathanielHill谢谢!
我试过这个解决方案,但查询参数被删除了。 例如/some/?query=1将在没有查询的情况下重定向到/some 。 你知道如何解决吗?

是的,这听起来像是一个问题@exentrich

我不会猜到这种行为,因为有人告诉我有一个隐含的^$包裹在正则表达式中(意味着您的示例不匹配)。 也许有一种方法可以自行访问查询字符串以将其添加回来:man_shrugging:祝你好运

尝试使用自定义快速服务器和 avinoamr/connect-slashes 使其工作,但似乎遇到了同样的问题

这当然是一个大问题,特别是因为/路由会抛出错误页面,这会损害 SEO(这是 Next 的主要吸引力之一)。

301 重定向和自定义快速服务器似乎都是黑客而不是修复。 就我而言,我在 Next 上构建了一个完整的工作应用程序,没有自定义 Express 服务器- 其他一切都运行良好,但现在我不得不创建一个新的 Express 服务器,只是因为尾部斜杠问题。 考虑到这是一种黑客攻击,所需的努力似乎不成比例。 如果可以优先考虑这一点,我会很高兴! 由于这个原因,我听到我的团队抱怨使用 Next 而不是像普通的 React/Angular 这样的东西,它肯定削弱了 Next 的情况。

PS:我非常喜欢和 Next 一起工作❤️

这当然是一个大问题,尤其是因为/路由会抛出错误页面并且会损害 SEO

它不会伤害您的 SEO。 谷歌将尾部斜杠视为不同的页面。 拥有 404 不会比您网站中的任何其他不存在的页面对 SEO 的影响更大。 此外,只要您从不使用尾部斜杠链接到它,谷歌就不会首先尝试抓取它。 这个问题虽然仍然是一个有效的问题,但远没有你们想象的那么重要。

@nik-john @NathanielHill @dkrish @exentrich

您不必使用 Express 服务器来执行 301 重定向。 取决于您的要求,但我已经能够通过自定义server.js来满足我的要求。

301 重定向也是 SEO 的最佳方式,因为您不会因斜线和非斜线路线而受到重复的内容处罚。

我喜欢 ❤️ Next.js,但我投票赞成在没有这个工作的情况下处理这个问题。

// server.js

const { createServer } = require('http');
const { parse } = require("url");
const next = require("next");

const dev = process.env.NODE_ENV !== 'production'
const port = parseInt(process.env.PORT, 10) || 3000;
const app = next({ dev, quiet: false });
const handle = app.getRequestHandler();

(async () => {
    await app.prepare();
    const server = createServer();

    server.on('request', async (req, res) => {

        const parsedUrl = parse(req.url, true);
        const { pathname, query } = parsedUrl;

        if (pathname.length > 1 && pathname.slice(-1) === "/") {
            console.log('server.js - redirect on "/"...', pathname, query);
            const queryString = await Object.keys(query).map(key => key + '=' + query[key]).join('&');
            res.writeHead(301, { Location: pathname.slice(0, -1) + (queryString ? '?'+ queryString : '') });
            res.end();
        }

        handle(req, res, parsedUrl);

    });

    await server.listen(port);
    console.log(`🚀 Ready on http://localhost:${port}`);

})();

@Janpot

它不会伤害您的 SEO。 谷歌将尾部斜杠视为不同的页面。 拥有 404 不会比您网站中的任何其他不存在的页面对 SEO 的影响更大。

我认为它不会特别伤害 SEO 天生的。 但它确实给开发人员带来了额外的压力,要求每次都正确地确定 URL 定义,这可能会导致人为错误。 不熟悉 Next 的开发人员不一定知道以下(看起来完全正常的)URL 将导致 404 页面。 <Link href='/people/'>

理想情况下,一个成熟的框架不应受到此类人为错误的影响。

此外,只要您从不使用尾部斜杠链接到它,谷歌就不会首先尝试抓取它。

再次 - 存在人们不小心链接到 _ www.mysite.com/people/_而不是 _ www.mysite.com/people_ 的问题(对于用户来说,这两者似乎完全相同 - 甚至大多数开发人员)。

这两种情况都_可以_影响搜索引擎优化。

现在,不考虑 SEO 影响,还有 URL 的语义含义 - _does_ _ www.mysite.com/people / _ 指向什么? 理想情况下,因为它指向一个目录,Next 应该返回pages > people > index.js (与 _www.mysite.com/people_ 的pages > people.js相反)但它什么都不返回,这是一个非常路由如何工作的高级缺陷。

主要的路由库已经为此做了一些规定——比如 React Router 中的isExact

虽然我明白你来自哪里,但我仍然认为这是一个需要解决的明显问题

这在next export的情况下也是完全无法避免的

存在人们不小心链接的问题......

存在人们不小心链接到任何不存在的 url 的问题,为什么/some/path//some/path/dhgfiuwo

还有 URL 的语义

这是非常主观的,据我所知,没有规范说明什么是语义差异。 根据URL规范,带和不带斜杠被认为是不同的 url。 我可以想到至少 7 种不同的有效行为:

  • 有和没有完全不同的内容
  • 有 404,没有解析
  • 有解析,没有 404
  • with 重定向到 without
  • 没有重定向到 with
  • with 和 without 具有相同的内容,规范指向 with
  • 有和没有具有相同的内容,规范指向无

将此与具有/pages/some-page.js/pages/some-page/index.js (或两者)的可能性配对。

next.js 应该支持所有这些用例吗? 它应该选择默认行为吗?

我并不反对这一点,但是在之前尝试实现这一点之后,我只是认为它比最初看起来的更细微。

存在人们不小心链接到任何不存在的 url 的问题,为什么 /some/path/ 比 /some/path/dhgfiuwo 不存在?

对于/some/path/dhgfiuwo - 人们希望dhgfiuwo路线可能会丢失。 (例如,在系统中找不到用户dhgfiuwo并且方式users/dhgfiuwo是错误的。系统中没有用户是预期的情况。)
对于案例/some/path/ - 人们希望这条路径与/some/path ,因为这是其他站点的默认行为。
因此, would/some/path/的失败比/some/path/dhgfiuwo更不存在。

我看到其他人发布了他们的解决方案,所以我想分享我的方法: https :

当涉及到 ?= 时,对动态路由页面的一些改进和支持应该在 IMO 上完成,但这只是为了展示这个想法。

要获得快速解决方案,您可以替换默认的_error页面(如@DevSpeak的示例)。

@DevSpeak ,我建议对您的存储库进行一些更改:

  • 避免 301 重定向——它们被浏览器永久缓存,会给你带来很多痛苦。 在大多数情况下,您只需要一个 302。
  • 您的errorCode 三元可以更新(直到上周它在文档中已经过时)
  • 这只是服务器端的,所以你可以用if (typeof window === 'undefined') { ... }包装它,从客户端包中摇树它

这是我在 Typescript 项目中使用的内容(基于内置错误页面):

/pages/_error.tsx (或删除 TypeScript 类型并将其命名为/pages/_error.jsx ):

import React from 'react';
import Head from 'next/head';
import { NextPageContext } from 'next';

const statusCodes: { [code: number]: string } = {
  400: 'Bad Request',
  404: 'This page could not be found',
  405: 'Method Not Allowed',
  500: 'Internal Server Error'
};

export type ErrorProps = {
  statusCode: number;
  title?: string;
};

/**
 * `Error` component used for handling errors.
 */
export default class Error<P = {}> extends React.Component<P & ErrorProps> {
  static displayName = 'ErrorPage';

  static getInitialProps({
    req,
    res,
    err
  }: NextPageContext): Promise<ErrorProps> | ErrorProps {
    const statusCode =
      res && res.statusCode ? res.statusCode : err ? err.statusCode! : 404;
    if (typeof window === 'undefined') {
      /**
       * Workaround for: https://github.com/zeit/next.js/issues/8913#issuecomment-537632531
       * Test vectors:
       * `/test/test/` -> `/test/test`
       * `/test/////test////` -> `/test/test`
       * `/test//test//?a=1&b=2` -> `/test?a=1&b=2`
       * `/test///#test` -> `/test#test`
       */
      const correctPath = (invalidPath: string) =>
        invalidPath
          .replace(/\/+$/, '')
          .replace(/\/+#/, '#')
          .replace(/\/+\?/, '?')
          .replace(/\/+/g, '/');
      if (req && res && req.url && correctPath(req.url) !== req.url) {
        res.writeHead(302, {
          Location: correctPath(req.url)
        });
        res.end();
      }
      const reqInfo = req
        ? `; Url: ${req.url}; IP: ${req.headers['x-forwarded-for'] ||
            (req.connection && req.connection.remoteAddress)};`
        : '';
      console.log(`Error rendered: ${statusCode}${reqInfo}`);
    }
    return { statusCode };
  }

  render() {
    const { statusCode } = this.props;
    const title =
      this.props.title ||
      statusCodes[statusCode] ||
      'An unexpected error has occurred';

    return (
      <div style={styles.error}>
        <Head>
          <title>
            {statusCode}: {title}
          </title>
        </Head>
        <div>
          <style dangerouslySetInnerHTML={{ __html: 'body { margin: 0 }' }} />
          {statusCode ? <h1 style={styles.h1}>{statusCode}</h1> : null}
          <div style={styles.desc}>
            <h2 style={styles.h2}>{title}.</h2>
          </div>
        </div>
      </div>
    );
  }
}

const styles: { [k: string]: React.CSSProperties } = {
  error: {
    color: '#000',
    background: '#fff',
    fontFamily:
      '-apple-system, BlinkMacSystemFont, Roboto, "Segoe UI", "Fira Sans", Avenir, "Helvetica Neue", "Lucida Grande", sans-serif',
    height: '100vh',
    textAlign: 'center',
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'center',
    justifyContent: 'center'
  },

  desc: {
    display: 'inline-block',
    textAlign: 'left',
    lineHeight: '49px',
    height: '49px',
    verticalAlign: 'middle'
  },

  h1: {
    display: 'inline-block',
    borderRight: '1px solid rgba(0, 0, 0,.3)',
    margin: 0,
    marginRight: '20px',
    padding: '10px 23px 10px 0',
    fontSize: '24px',
    fontWeight: 500,
    verticalAlign: 'top'
  },

  h2: {
    fontSize: '14px',
    fontWeight: 'normal',
    lineHeight: 'inherit',
    margin: 0,
    padding: 0
  }
};

请注意,当页面被点击时,这也会记录一个错误,因此您可以检查您的日志以修复任何链接/其他问题。

@DevSpeak @bitjson感谢您的建议。 这当然是解决这个问题的一种方法,当然可以很好地解决这个问题。 但是考虑到_error.jsx最初是为了处理 _errors_ 而不是内部路由逻辑,在我看来,拥有所有这些代码是hacky 并且相当声明性的。 不应该期望每个用户在每个代码库中都这样做 - 这应该是开箱即用的。 = 我认为这个条件需要与路由逻辑一起构建,并可以选择退出,如 React Router。

@纳撒尼尔希尔

这在下次出口的情况下也是完全无法避免的

等等 - 我从阅读文档中了解到有特定的代码来处理尾部斜杠条件:

页面将导出为 html 文件,即 /about 将变为 /about.html。

可以配置 Next.js 将页面导出为 index.html 文件并需要尾部斜杠,即 /about 变成 /about/index.html 并且可以通过 /about/ 路由。 这是 Next.js 9 之前的默认行为。您可以使用以下 next.config.js 切换回此行为:

// next.config.js
module.exports = {
  exportTrailingSlash: true,
}

即使这不是通过next export进行静态 HTML 导出的真正选项,我也不同意仅仅因为 Next 支持这个(惊人的)功能,其他模式需要受到影响的逻辑(我不知道使用统计数据,但我认为更多的人使用常规的 with-server 模式而不是 serverless),尤其是当众所周知这是一个常见的用例时

仅供参考:您可能会对 RFC 感兴趣https://github.com/zeit/next.js/issues/9081

// next.config.js
module.exports = {
  async redirects() {
    return [
      {
        source: "/:path*/",
        destination: "/:path",
        statusCode: 301
      }
    ];
  }
};

@Janpot喜欢它 - 这将使我们半途而废,即无需创建自定义服务器即可对重定向提供某种支持。 这仍然是必要的,因为对于用户添加的每条路线,他们都必须在next.config.js设置重定向 - 或者我们可以只使用正则表达式来捕获@bitjson提到的所有情况:

          .replace(/\/+$/, '')
          .replace(/\/+#/, '#')
          .replace(/\/+\?/, '?')
          .replace(/\/+/g, '/')

在任何一种情况下,如果核心团队正在优先考虑这个 RFC,我强烈建议我们更进一步,让它成为一个内置的 _config_,人们可以 _opt out_像这样

// next.config.js
module.exports = {
  ignoreStrictRoutes: false, // default value: true
};

总而言之,我认为这是向前迈出的一大步——好东西@Timer!! 🔥

@nik-john 我在"/:path*/"指定的路径应该捕获所有( :path捕获单个段, *使其捕获 0 到 n 个实例。)

@Janpot啊,我的错🤦‍♂ 我猜我们还需要考虑该正则表达式中的任何尾随查询参数

另外,我仍然支持第二部分:

在任何一种情况下,如果核心团队正在优先考虑这个 RFC,我强烈建议我们更进一步,让它成为一个内置的配置,人们可以像这样选择退出

// next.config.js
module.exports = {
  ignoreStrictRoutes: false, // default value: true
};

如果您使用自定义服务器并希望忽略严格路由,您还可以使用自定义路由处理程序而不是进行重定向。

app.render(req, res, urlWithoutTrailingSlash, query);

这样我们就可以同时支持/path/path/并解析到同一个页面。

Oauth 联合提供者通常需要尾随正斜杠,因此这种行为使简单的流程变得非常复杂。 实现这种行为的技术挑战是什么? 或者这是下一步的设计决定?

到目前为止,我还没有在这个线程中看到它提到它,但是在使用 Now 部署后我没有遇到这个问题,我只是在使用now dev进行测试时在本地遇到它。

const removeTrailingSlashes = (req, res, expressNext) => {
  if (req.path.substr(-1) === '/' && req.path.length > 1) {
    const query = req.url.slice(req.path.length);
    res.redirect(301, req.path.slice(0, -1) + query);
  } else {
    expressNext();
  }
};

从stackoverflow得到这个并且完美地工作。 此解决方案适用于 express。

@GaneshKathar如果您考虑 Next.js 不使用 express,我不知道这将如何工作

我认为我们不能就这一点达成一致,它应该是可配置的。

我实际上总是想要尾部斜杠,当所有页面都以尾部斜杠结尾时,相对 url 更容易推理。

例如, /about/index.tsx/about而不是/about/是没有意义的,但是现在可以理解 next 期望没有尾部斜杠。 如果所有页面都以斜杠结尾,它将允许页面在未来包含子页面,我认为这是页面更可扩展的方式。

/about/index.tsx文件中建立相对链接现在很麻烦。 如果您创建一个链接./mysubpage/它会指向站​​点的根目录。 这使得子页面不可重命名。 我不能让目录/about/充满我可以重命名的页面,因为我也应该去编辑相对链接。

此外, wget -r站点通过始终尾部斜杠产生合理的结果,产生 index.html 文件。

然而,更改此设置会带来巨大的破坏性更改,因为所有站点都希望使用非尾随斜杠,因此它必须是可配置的。

我正在使用版本 9,但此问题仍未解决

我能够通过在我的next.config.js上使用以下内容来使其工作:

exportPathMap: async function() {
  const paths = {
    '/': { page: '/' },
    '/authors/index.html': { page: '/authors' },
  };

  return paths;
},

访问/authors给出 302 指向location/authors/ 。 我正在使用http-serve ,不确定此行为是否特定于服务器。

当我遇到这个问题时,我想出了这个解决方案

在我的_error.js页面中

Error.getInitialProps = ({ res, err, asPath }) => {
    const statusCode = res ? res.statusCode : err ? err.statusCode : 404;

    const checkForTrailingSlashes = () => {
        if (asPath.match(/\/$/)) { // check if the path ends with trailing slash
            const withoutTrailingSlash = asPath.substr(0, asPath.length - 1);
            if (res) {
                res.writeHead(302, {
                    Location: withoutTrailingSlash
                })
                res.end()
            } else {
                Router.push(withoutTrailingSlash)
            }
        }
    }

    if (statusCode && statusCode === 404) {
        checkForTrailingSlashes();
    } else {
        // 
    }
    return { statusCode };
}

这是克服这个问题的好方法吗?

这个怎么样?

页面/_app.jsx

```从'react'导入React;
从“下一个/应用程序”导入应用程序;

导出默认类 MyApp 扩展 App {
使成为() {
const { Component, pageProps, router: { asPath } } = this.props;

// Next.js currently does not allow trailing slash in a route.
// This is a client side redirect in case trailing slash occurs.
if (asPath.length > 1 && asPath.endsWith('/')) {
  const urlWithoutEndingSlash = asPath.replace(/\/*$/gim, '');

  if (typeof window !== 'undefined') {
    window.location.replace(urlWithoutEndingSlash);
  }
  return null;
}

return <Component {...pageProps} />;

}
}
``

@cnblackxp感谢您的建议。 那帮助了我。 这是我如何实现它以保持非尾随 404s 的默认行为(即我只是重新导出默认的Error实现):

import Error from "next/error";
import Router from "next/router";

export default Error;

Error.getInitialProps = ({ res, err, asPath }) => {
  const statusCode = res ? res.statusCode : err ? err.statusCode : 404;

  if (statusCode && statusCode === 404) {
    if (asPath.match(/\/$/)) {
      const withoutTrailingSlash = asPath.substr(0, asPath.length - 1);
      if (res) {
        res.writeHead(302, {
          Location: withoutTrailingSlash
        });
        res.end();
      } else {
        Router.push(withoutTrailingSlash);
      }
    }
  }

  return { statusCode };
};

是的,只要没有其他决定,@ cansin就可以了 :) 欢呼!

@AlexSapoznikov的解决方法的小改进:

  render() {
    const { Component, pageProps, router: { asPath } } = this.props;

    // Next.js currently does not allow trailing slash in a route.
    // This is a client side redirect in case trailing slash occurs.
    if (pageProps.statusCode === 404 && asPath.length > 1 && asPath.endsWith('/')) {

这里唯一的区别是检查状态代码是否为 404。我遇到了使用 Link 进行动态路由的问题,由于重定向,它们总是在服务器上呈现。 如果您希望客户端路由工作,则不能向 Link href属性添加尾部斜杠,但是您需要确保在这种情况下不重定向。

在 Error 组件中实现变通方法的问题是它会在开发中抛出通知错误,这让我很烦恼。 对我之前的客户端重定向的一些改进:

改进的是现在它在客户端使用 next/router 并且 url 替换发生而无需重新加载。

页面/_app.jsx

import App from 'next/app';
import Router from 'next/router';

export default class MyApp extends App {
  render() {
    const { Component, pageProps, router: { asPath, route } } = this.props;

    // Next.js currently does not allow trailing slash in a route.
    // This is a client side redirect in case trailing slash occurs.
    if (pageProps.statusCode === 404 && asPath.length > 1 && asPath.endsWith('/')) {
      const routeWithoutEndingSlash = route.replace(/\/*$/gim, '');
      const asPathWithoutEndingSlash = asPath.replace(/\/*$/gim, '');

      if (typeof window !== 'undefined') {
        Router.replace(routeWithoutEndingSlash, asPathWithoutEndingSlash);
      }
      return null;
    }

    return <Component {...pageProps} />;
  }
}

还要感谢@mbrowne的 404 修复:)

采用@cansin的解决方案并添加了处理查询参数的能力

MyError.getInitialProps = async ({ res, err, asPath }) => {
  // Capture 404 of pages with traling slash and redirect them
  const statusCode = res 
    ? res.statusCode
    : (err ? err.statusCode : 404);

  if (statusCode && statusCode === 404) {
    const [path, query = ''] = asPath.split('?');                                                                                                                                                                                             
    if (path.match(/\/$/)) {
      const withoutTrailingSlash = path.substr(0, path.length - 1); 
      if (res) {
        res.writeHead(302, {
          Location: `${withoutTrailingSlash}${query ? `?${query}` : ''}`,
        }); 
        res.end();
      } else {
        Router.push(`${withoutTrailingSlash}${query ? `?${query}` : ''}`);
      }   
    }   
  }

@pinpointcoder你能提供一个带有斜杠和查询参数同时发生的 url 的例子吗? 你在想/blog/?123的路线吗?

感谢大家以上的一些解决方法。 他们工作了!

但是,我们是否有任何官方方法可以从 Next 的团队解决此问题? 这个问题已经存在多年了。

目录页面在下次导出时不带有尾部斜杠

@pinpointcoder你能提供一个带有斜杠和查询参数同时发生的 url 的例子吗? 你在想/blog/?123的路线吗?

@coodoo不是他,但是,不幸的是,这种情况

由于我们即将迁移大量博客文章,其中规范 URL 当前包含一个斜杠,这让我感到非常痛苦。

我决定实现一个自定义服务器来处理这个问题,结果证明这很容易,而且你仍然可以使用 next.js 的基于文件的路由系统。 这样你就可以重写 next.js 看到的 URL,真正的 URL 在末尾仍然有一个斜杠:

const { createServer } = require('http')
const { parse } = require('url')
const next = require('next')
const conf = require('./next.config.js')

const PORT = process.env.PORT || 5000

const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev, conf })
const handle = app.getRequestHandler()

app.prepare().then(() => {
    createServer((req, res) => {
        // If there is a slash at the end of the URL, remove it before sending it to the handle() function.
        // This is a workaround for https://github.com/zeit/next.js/issues/5214
        const url =
            req.url !== '/' && req.url.endsWith('/')
                ? req.url.slice(0, -1)
                : req.url
        // Be sure to pass `true` as the second argument to `url.parse`.
        // This tells it to parse the query portion of the URL.
        const parsedUrl = parse(url, true)

        handle(req, res, parsedUrl)
    }).listen(PORT, err => {
        if (err) throw err
        console.log(`> Ready on http://localhost:${PORT}`)
    })
})

请参阅https://nextjs.org/docs/advanced-features/custom-server

@mbrowne我们实际上有很多使用自定义服务器的原因,但到目前为止阻止我实现的主要因素是您失去了自动静态优化。 您知道是否可以手动指定静态路由?

我们目前不需要对我们的应用程序进行自动静态优化,所以我还没有研究它。

我也在使用自定义服务器,但是当您将修改后的(不带前导斜杠)url 传递给handle ,SSR 从客户端看到不同的 url。
我更喜欢next路由器将 url 与前导斜杠匹配,而没有那些讨厌的黑客。

2020 年了,这个 bug 还是会发生。 逆天

这是一个真正需要修复的坏错误。 /products有效,但/products/无效。 有了这个链接

<Link href="/products">
  <a>Products</a>
</Link>

我得到

index.js:1 Warning: Prop `href` did not match. Server: "/products" Client: "/products/"

但是,如果我将链接指向/products/ ,访问该链接,并在开发过程中刷新页面,则会出现 404。这是一种非常痛苦的开发体验。

这个问题最早是在 1.5 年前报道的; 我们可以请官方修复吗? 它仍然存在于 9.3.4 中。

出于 SEO 的原因,我重定向到非尾随斜杠 url 而不是显示内容。

app.prepare().then(() => {
  createServer((req, res) => {
    if (req.url !== '/' && req.url.endsWith('/')) {
      res.writeHead(301, { Location: req.url.slice(0, -1) })
      res.end()
    }
    handle(req, res, parse(req.url, true))
  }).listen(PORT, err => {
    if (err) throw err
    console.log(`> Ready on http://localhost:${PORT}`)
  })
})

对于 SEO, rel="canonical"可能会有所帮助,但仍需要解决此 404 问题。

这是一个真正需要修复的坏错误。 /products有效,但/products/无效。 有了这个链接

<Link href="/products">
  <a>Products</a>
</Link>

我得到

index.js:1 Warning: Prop `href` did not match. Server: "/products" Client: "/products/"

但是,如果我将链接指向/products/ ,访问该链接,并在开发过程中刷新页面,则会出现 404。这是一种非常痛苦的开发体验。

这个问题最早是在 1.5 年前报道的; 我们可以请官方修复吗? 它仍然存在于 9.3.4 中。

我目前也遇到了这个问题。

这是我修复它的方法, https: //medium.com/@thisisayush/handling -404-trailing-slash-error-in-nextjs-f8844545afe3

这是我修复它的方法, https: //medium.com/@thisisayush/handling -404-trailing-slash-error-in-nextjs-f8844545afe3

谢谢,尽管在本地开发时这需要自定义服务器,但不应该需要。

@timneutkens 是否有可能将此问题的修复程序纳入开发计划?

更重要的是,重定向解决方案不适用于那些维护已设置为添加斜杠而不是在生产中删除斜杠的站点的站点。 我认为框架不应该随意规定这个选择。

@AlexSapoznikov解决方案对我们使用 Netlify 效果很好(默认情况下它添加了尾部斜杠)。 这是一个添加了对查询参数的支持的高级版本:

import App from "next/app";

export default class MyApp extends App {
  render() {
    const { Component, pageProps, router, router: { asPath } } = this.props;

    // Next.js currently does not allow trailing slash in a route, but Netlify appends trailing slashes. This is a
    // client side redirect in case trailing slash occurs. See https://github.com/zeit/next.js/issues/5214 for details
    if (asPath && asPath.length > 1) {
      const [path, query = ""] = asPath.split("?");
      if (path.endsWith("/")) {
        const asPathWithoutTrailingSlash = path.replace(/\/*$/gim, "") + (query ? `?${query}` : "");
        if (typeof window !== "undefined") {
          router.replace(asPathWithoutTrailingSlash, undefined, { shallow: true });
          return null;
        }
      }
    }

    return <Component {...pageProps} />;
  }
}

我很抱歉,因为我是 Next JS 新手,尽管我在其他 SDK 和平台上有软件开发经验。

我认为这个“错误”最让我惊讶。 对我来说,它违反了“最小惊讶原则”。 我只是希望我的 /about/ 和 /about 工作相同,因为我将 index.tsx 放入我的 /pages/about/ 文件夹中。

我首先在 1990 年代后期开始制作网站,将 HTML FTP 连接到我的服务器,然后转向 PHP 和 Apache,最终使用 Java 服务器。 现在我专注于移动应用程序。 这种行为不是默认行为,我觉得很奇怪,我必须编写一个自定义服务器页面才能在我的开发服务器上修复它。

我计划进行静态导出,因此即使我不编写自定义服务器,它也不会出现在生产中。 不过,它确实让开发和调试变得更加烦人。

我们可以得到一个“下一个开发”标志来修复这个问题,这样我们懒惰的开发人员就不需要为开发/调试时间编写额外的路由逻辑吗?

谢谢!

ps:是的,我知道/about/about/是完全不同的 URL。 当我将index.tsx文件放入/pages/about/文件夹时,我真的很困惑,发现它只适用于/about路径,但不适用于/about/ 。 如果情况相反,我不会感到惊讶。

pps:当我有一个<Link></Link>组件指向/about/并且它按预期工作时,这会更加令人困惑。 然后当我在浏览器上点击刷新时,它立即 404,即使 URL 没有改变。 这是非常令人惊讶的。 :-D

但是等等,情况变得更糟! 我们在_error.js中添加了一个自定义的checkForTrailingSlash函数,它将去除尾部斜杠并重定向。 这工作了一段时间,直到我们(最终)添加了一个自定义 404 页面,并发现使用自定义 404 页面,Next.js 完全绕过了Error 。 这意味着Error.getInitialProps任何自定义逻辑都将不再起作用——包括检查尾部斜杠。

猜猜我会尝试其他人提到的_app.js解决方案,因为自定义服务器还不太可能。

@AlexSapoznikov解决方案对我们使用 Netlify 效果很好(默认情况下它添加了尾部斜杠)。 这是一个添加了对查询参数的支持的高级版本:

import App from "next/app";

export default class MyApp extends App {
  render() {
    const { Component, pageProps, router, router: { asPath } } = this.props;

    // Next.js currently does not allow trailing slash in a route, but Netlify appends trailing slashes. This is a
    // client side redirect in case trailing slash occurs. See https://github.com/zeit/next.js/issues/5214 for details
    if (asPath && asPath.length > 1) {
      const [path, query = ""] = asPath.split("?");
      if (path.endsWith("/")) {
        const asPathWithoutTrailingSlash = path.replace(/\/*$/gim, "") + (query ? `?${query}` : "");
        if (typeof window !== "undefined") {
          router.replace(asPathWithoutTrailingSlash, undefined, { shallow: true });
          return null;
        }
      }
    }

    return <Component {...pageProps} />;
  }
}

您的代码示例中存在一个严重错误:对带有查询参数的索引路由的请求将引发错误,因为您最终试图仅将查询字符串作为asPath传递给 Next.js。

这修复了它:

  if (asPath && asPath.length > 1) {
    const [path, query = ''] = asPath.split('?');
    if (path.endsWith('/') && path.length > 1) {
      const asPathWithoutTrailingSlash =
        path.replace(/\/*$/gim, '') + (query ? `?${query}` : '');
      if (typeof window !== 'undefined') {
        router.replace(asPathWithoutTrailingSlash, undefined, {
          shallow: true,
        });
        return null;
      }
    }
  }

为了使用 SSR 进行这项工作,我必须将以下内容添加到@pjaws & @AlexSapoznikov解决方案中:

  static async getInitialProps({ Component, ctx, router }) {
    /* Fixes the trailing-slash-404 bug for server-side rendering. */
    const { asPath } = router;
    if (asPath && asPath.length > 1) {
      const [path, query = ""] = asPath.split("?");
      if (path.endsWith("/") && path.length > 1) {
        const asPathWithoutTrailingSlash =
          path.replace(/\/*$/gim, "") + (query ? `?${query}` : "");
        if (ctx.res) {
          ctx.res.writeHead(301, {
            Location: asPathWithoutTrailingSlash,
          });
          ctx.res.end();
        }
      }
    }
    return {
      pageProps: Component.getInitialProps
        ? await Component.getInitialProps(ctx)
        : {},
    };
  }

以某种方式将此功能推广到一个在 SSR 和 CSR 期间都可以工作的函数并在两个地方( getInitialPropsrender )调用它可能是个好主意。

经过

这将解决,但标题错误。 唔
image

@AlexSapoznikov @pjaws

您的解决方案使我们陷入无限循环:

  if (asPath && asPath.length > 1) {
    const [path, query = ''] = asPath.split('?');
    if (path.endsWith('/') && path.length > 1) {
      const asPathWithoutTrailingSlash =
        path.replace(/\/*$/gim, '') + (query ? `?${query}` : '');
      if (typeof window !== 'undefined') {
        router.replace(asPathWithoutTrailingSlash, undefined, {
          shallow: true,
        });
        return null;
      }
    }
  }

语境

由于我们无法控制的原因,我们必须在next.config.js使用exportTrailingSlash选项。

我们想要一个指向另一个页面的链接,但我们希望链接是/somepage?param=whatever

似乎下一个链接将其转换为/somepage/?param=whatever并且我们找不到页面。

使用上面的解决方案解决了 params 问题,但是当转到像/somepage/这样的部署页面时,它进入了一个无限循环。

我认为@ronyeh在这里提出了一个非常好的观点,所以我真的想要一个官方解决方案来解决这个问题:(

为了使用 SSR 进行这项工作,我必须将以下内容添加到@pjaws & @AlexSapoznikov解决方案中:

  static async getInitialProps({ Component, ctx, router }) {
    /* Fixes the trailing-slash-404 bug for server-side rendering. */
    const { asPath } = router;
    if (asPath && asPath.length > 1) {
      const [path, query = ""] = asPath.split("?");
      if (path.endsWith("/") && path.length > 1) {
        const asPathWithoutTrailingSlash =
          path.replace(/\/*$/gim, "") + (query ? `?${query}` : "");
        if (ctx.res) {
          ctx.res.writeHead(301, {
            Location: asPathWithoutTrailingSlash,
          });
          ctx.res.end();
        }
      }
    }
    return {
      pageProps: Component.getInitialProps
        ? await Component.getInitialProps(ctx)
        : {},
    };
  }

以某种方式将此功能推广到一个在 SSR 和 CSR 期间都可以工作的函数并在两个地方( getInitialPropsrender )调用它可能是个好主意。

这适用于带有 getServerSideProps 的页面,现在带有斜杠的 url 返回没有 404 的相同页面。
但是有一个小故障,我有几个页面使用动态路由和 getStaticPaths,我不能在它们上使用 getServerSideProps,因此当使用尾部斜杠浏览这些动态路由时,它们首先返回 404,然后重定向到页面.

我正在使用 /api/test 文件夹

  • 页面/api/test.tsx
  • 页面/api/test/[id].tsx

它适用于

  • 获取/api/测试
  • 获取/api/test/123
  • 获取/api/test/123/

我才发现这行不通

  • 获取/api/测试/

不确定这是否是相关问题
P/D exportTrailingSlash = true 不解决

这是一个非常古老的问题,有什么原因这么长时间没有解决吗?

我不确定什么不再起作用。

我的低估是要求如下:

| | exportTrailingSlash: 假 | exportTrailingSlash: true |
|-------------------------|---------------------- -----|---------------------------|
| url 以 / 结尾不应该工作| 应该工作|
| url 不以 / 结尾应该工作| 不应该工作|

这在以下情况下按预期工作:

  • 在本地我们使用exportTrailingSlash: false
  • 对于部署(生产构建),我们使用exportTrailingSlash: true并且 nginx 将url/url/index.html

从我在@andrescabana86 中看到的情况GET /api/test/123/GET /api/test/不起作用,也不应该起作用。

@Izhaki我都试过了,在产品上部署......但对我来说不起作用

  • 获取/api/测试/

我正在使用exportTrailingSlash: true

如果你愿意,我可以尝试创建一个公共仓库,也许我在中间忘记了一些东西。

谢谢您的回答

@andrescabana86我不确定公共存储库在这里有多大帮助 - 这很可能是您部署到的服务器上的一些配置。

我们正在使用package.json此脚本在本地测试我们的生产版本(使用exportTrailingSlash: true ):

"serve:out": "docker run --rm -v $(pwd)/out:/static -p 5000:80 flashspys/nginx-static"

请让我知道在您的浏览器中转到http://localhost:5000/api/test/有效。

(请注意, $(pwd)是Mac / Linux的-看到适用于Windows)

@Izhaki问题在于(正如最初的报告所暗示的那样)“合法页面链接中的尾部斜杠适用于客户端导航,但导致未找到捆绑包和硬刷新(ssr)时出现 404”。 因此,客户端路由更改的行为与硬刷新之间存在不匹配。 我不确定最新版本的 Next.js 是否仍然存在问题。 一旦我测试它,我可以在这里报告。

刚刚测试了 9.4.1 和exportTrailingSlash: true

在本地开发时转到http://localhost:6500/admin/返回 404。

但是导出时相同的路径有效。

请注意, exportTrailingSlash提示这仅适用于 _exports_。

我们所做的是使用:

exportTrailingSlash: process.env.NODE_ENV === 'production'

这意味着当我们在本地开发时,事情会按预期进行。 并在部署时正常工作(通过导出)。

这不是解决此问题的正确可行的解决方案吗?

如果一个 URL 不能用于开发但可以用于生产,你不认为这违反了最小惊喜原则吗? 我认为这仍然应该被视为一个错误。

^ 也就是说,我很确定以前在生产中页面刷新与 router.push 事件之间存在冲突行为。 我不知道现在是否仍然如此。

@andrescabana86 @Izhaki exportTrailingSlash与此无关。 该选项与 Next.js 应用程序的静态导出相关。 为真时,生成example/index.html ,为假时,生成example.html 。 我的理解是exportTrailingSlash与开发模式无关。

我认为一个混乱的来源是,当您有exportTrailingSlash next.js 时,会在链接中添加一个尾部斜杠。 这也发生在开发中,我不确定它应该这样做吗? 但无论如何,这不仅仅是关于example/index.htmlexample.html - 您还需要修改链接。

如果一个 URL 不能用于开发但可以用于生产,你不认为这违反了最小惊喜原则吗? 我认为这仍然应该被视为一个错误。

我可能错了,但是 exportTrailingSlash 选项适用于未配置为在 URL 为/something时提供/something.html nginx 服务器。

用于本地开发的下一个服务器不是这种情况。 因此,什么有效,什么无效取决于为您的应用提供什么服务。

你可以假设当exportTrailingSlash为真时,下一个服务器应该支持以斜杠结尾的路由(尽管这会使export中的exportTrailingSlash有点无关紧要)。

FWIW 这已经在进行中 #13333

我不是很有经验的编码员,主要使用 Next.js 进行多页登陆。 显然,我几乎一直在使用以下解决方法,但不知道其效果。 这是它的精简版:

// In your server.js
server.get('/:id', (req, res) => {
  const actualPage = `/${req.params.id}`
  app.render(req, res, actualPage)
})

在我的情况下,代码有点复杂,因为我使用它来支持额外的静态 url 前缀等。但是这个精简的版本似乎可以很好地解决所讨论的问题,无论exportTrailingSlash设置及其对Link的影响。 例如 URL /about/about/工作得很好。

在目前的形式中,它本质上模仿了 Next.js 的原生路由。 缺点:它需要自定义server.js ,并且您必须手动支持“更深”的 URL(带有额外的“子文件夹”),例如/company/about/ 。 但是对于那些已经在他们的项目中使用自定义server.js人来说,这似乎是一个相对简单的解决方案。

为了使用 SSR 进行这项工作,我必须将以下内容添加到@pjaws & @AlexSapoznikov解决方案中:

  static async getInitialProps({ Component, ctx, router }) {
    /* Fixes the trailing-slash-404 bug for server-side rendering. */
    const { asPath } = router;
    if (asPath && asPath.length > 1) {
      const [path, query = ""] = asPath.split("?");
      if (path.endsWith("/") && path.length > 1) {
        const asPathWithoutTrailingSlash =
          path.replace(/\/*$/gim, "") + (query ? `?${query}` : "");
        if (ctx.res) {
          ctx.res.writeHead(301, {
            Location: asPathWithoutTrailingSlash,
          });
          ctx.res.end();
        }
      }
    }
    return {
      pageProps: Component.getInitialProps
        ? await Component.getInitialProps(ctx)
        : {},
    };
  }

以某种方式将此功能推广到一个在 SSR 和 CSR 期间都可以工作的函数并在两个地方( getInitialPropsrender )调用它可能是个好主意。

这适用于带有 getServerSideProps 的页面,现在带有斜杠的 url 返回没有 404 的相同页面。
但是有一个小故障,我有几个页面使用动态路由和 getStaticPaths,我不能在它们上使用 getServerSideProps,因此当使用尾部斜杠浏览这些动态路由时,它们首先返回 404,然后重定向到页面.

@gauravkrp这实际上是一个非常重要的补充,因为@AlexSapoznikov解决方案实际上仍会将页面的 404 返回给 Google(因为重定向发生在客户端上)。 我想 SEO 是我们很多人首先使用 Next.js 的一个主要原因。

我也认为把它放在getInitialProps应该可以正常工作,此时主函数中的部分是不必要的。 这里的主要警告是,您将失去自动静态优化,但可能比一堆 404 更好。

对于一些分享...

我的项目是Express + Next.js
express 4.17.1
next 9.4.5-canary.7

开发时

动态运行时

// next.config.js
module.exports = {
  exportTrailingSlash: false,
};

// app.js
const Next = require('next').default;
const NextApp = Next({ dev });
const NextHandler = NextApp.getRequestHandler();
NextApp.prepare();
app.get('*', (req, res) => NextHandler(req, res));

生产时

静态导出
运行next buildnext export -o dist/

// next.config.js
module.exports = {
  exportTrailingSlash: true,
};

// app.js
app.use('/_next', express.static('dist/_next', { etag: true, index: false, maxAge: '365d', redirect: false, dotfiles: 'ignore' }));
app.use('/fonts', express.static('dist/fonts', { etag: true, index: false, maxAge: '365d', redirect: false, dotfiles: 'ignore' }));
app.use('/img', express.static('dist/img', { etag: true, index: false, maxAge: '365d', redirect: false, dotfiles: 'ignore' }));
app.use(express.static('./dist', { index: ['index.html'] }));
app.use((req, res) => {
  res.Redirect('/404'); // <- Express will auto handle both /404 or /404/
});

综上所述

通过单击客户端应用程序重定向时我没有问题,
硬刷新也在static route

但是在dynamic route上硬刷新时会出现 404,
/album/[id].jsx/album/123
所以我期待通过使用以下机制来解决这个问题。

例如
当在/album/123处点击 404 时,
服务器应该继续提供html内容,
浏览器将继续加载页面而不会出现问题,
当 Next.js 启动时next/router应该自动处理它。

这个问题在生产中是否有任何临时解决方案?

我们即将推出一个功能来解决这个问题——一天左右!

这个问题在生产中是否有任何临时解决方案?

这个线程中有很多,但我目前正在使用@gauravkrp最近发布的内容,它对我来说效果很好。

您可以在此处跟踪 PR:#13333

这现已在next@^9.4.5-canary.17得到解决!

功能从金丝雀到精通需要多长时间?

这现已在next@^9.4.5-canary.17得到解决!

以及它究竟是如何解决的? 只是删除尾部斜杠? 如果我访问“ www.site.com/help/ ”,我会被重定向到:“ www.site.com/help ”,我们可以在那里选择离开结尾斜杠吗? 访问“ www.site.com/help/ ”或“ www.site.com/help ”将离开或重定向或在末尾添加“/”以具有:“ www.site.com/help/

@Valnexus见 #13333,它包括一个实验选项:

module.exports = {
  experimental: {
    trailingSlash: true
  }
}

功能从金丝雀到精通需要多长时间?

当它准备好了。 处理中仍有一些边缘情况正在解决。 一旦这些被修复,它就可以稳定下来。

@timneutkens @Janpot

我尝试了最新的 next canary (9.4.5-canary.27) 但是当我创建test页面并访问www.example/test/它重定向到www.example/test
我认为这两种情况的行为应该是相同的。

当访问www.example/test/它应该停留在www.example/test/
当访问www.example/test它应该停留在www.example/test
我在 Nuxt.js 上对其进行了测试,它的工作方式与我上面描述的行为相同。

我认为这两种情况的行为应该是相同的。

重定向的原因是确保搜索引擎不会看到重复的内容。 你的确切用例是什么?

如果它还没有合并到稳定版本,我不明白为什么它是一个封闭的问题。 如果我理解正确,它现在只在金丝雀版本中修复,对吗?

当相关的拉取请求登陆时,问题就会关闭,因为它们可以立即在金丝雀上使用。 如果您需要此功能,请升级到金丝雀频道。

听起来不错。 谢谢,@Timer!

@Janpot我看到https://github.com/issues/https://github.com/issues可以在没有重定向的情况下访问相同的行为。

https://twitter.com/explore/https://twitter.com/explore ,这个也是。

如果搜索引擎有问题,为什么 Github 和 Twitter 没有修复它?
我认为这是任何网站的默认行为。

没有特定的用例,只是我认为它应该以这种方式工作。

如果搜索引擎有问题,为什么 Github 和 Twitter 没有修复它?

@armspkt这不是问题,因为有多种方法可以解决。 例如 Twitter 使用<link rel="canonical">属性来告诉搜索机器人他们应该抓取哪个页面,其他版本应该被标记为重复。

因此,重定向是在您的网站上进行 SEO 的可行方法。 您可以在此处阅读更多信息。

@ziserman如果我们有多种方法来解决它,我们应该保持相同的 url 而不重定向以提高用户体验。

@Janpot https://github.com/nuxt-community/nuxt-i18n/issues/422

Nuxtjs 有几个选项可供选择(未定义、真、假)

Nextjs 是否也应该有多种选择?

重定向的原因是确保搜索引擎不会看到重复的内容。 你的确切用例是什么?

@Janpot我们的 API 在很多地方都有斜杠。 由于尾随斜杠 (/api/test/ -> /api/test) 不匹配,最新版本在后端引发了大量 404

我不知道它是否适用于每个人,但我找到了适合我的解决方案。 把它放在_app.js文件中。

static async getInitialProps(ctx) {
    const appProps = await App.getInitialProps(ctx);

    // Remove trailing slash
    const path = ctx.router.asPath,
            res = ctx.ctx.res;

    if (path.length > 1 && /\/$/.test(path)) {
        res.writeHead(301, {Location: path.slice(0, -1)})
        res.end();
    }

    return {...appProps};
}

@mlbonniec我已将您的评论最小化,因为它会导致 Next.js 应用程序中的严重性能下降。

最新的next@canary版本修复了这个错误,请升级!

@mlbonniec我已将您的评论最小化,因为它会导致 Next.js 应用程序中的严重性能下降。

最新的next@canary版本修复了这个错误,请升级!

没问题!
但是,我之前更新了,并没有解决问题。
npm update

如果最新的 Next.js canary 没有为您修复错误,请打开一个新问题,以便我们查看。 🙏

快速提问,带有next export项目将如何处理这种变化? 通过为每个页面的尾部斜杠创建一个全新的页面? 我不认为导出的应用程序可以指定 HTTP 重定向(或重写)。

使用next export将在客户端正确更新所有<Link /> ,但服务器端重定向将需要手动配置。 使用无服务器目标或next start部署的项目将自动配置这些设置。

@Timer一旦达到完整版本,我们还需要使用实验选项吗?

@Timer一旦达到完整版本,我们还需要使用实验选项吗?

不,将按原样提供。

我猜trailingSlash选项不适用于next export ? 在 github 页面中将/page/重定向到/page (或反之亦然)的最佳方法是什么?

我猜trailingSlash选项不适用于next export ? 在 github 页面中将/page/重定向到/page (或反之亦然)的最佳方法是什么?

据我所知,github 页面没有重定向功能。 这确实在 vercel.com 上开箱即用,尽管这对于业余项目也是免费的(如 github pages 是)。

使用next export将在客户端正确更新所有<Link /> ,但服务器端重定向将需要手动配置。 使用无服务器目标或next start部署的项目将自动配置这些设置。

@Timer你能解释更多吗? 如何手动配置? 所以这是我的情况。 在我的网站上,我使用next-i18next 。 在我使用next build && next export部署后,所有内部链接都有效,但是当手动输入 URL 时,它们都无效并导致 404 错误。 从这里开始,我决定使用trailingSlash:true ,因此手动输入/pricing现在可以使用,但/zh/pricing会导致 404 错误。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

robinvdvleuten picture robinvdvleuten  ·  74评论

ematipico picture ematipico  ·  66评论

nickredmark picture nickredmark  ·  60评论

arunoda picture arunoda  ·  103评论

Timer picture Timer  ·  87评论