Next.js: trailing slash in link untuk halaman yang sah berfungsi untuk navigasi sisi klien tetapi mengarah ke bundel yang tidak ditemukan dan 404 pada penyegaran keras (ssr)

Dibuat pada 20 Sep 2018  ·  119Komentar  ·  Sumber: vercel/next.js

trailing slash in link untuk halaman yang sah berfungsi untuk navigasi sisi klien tetapi mengarah ke bundel yang tidak ditemukan dan 404 pada penyegaran keras (ssr)

Laporan bug

Jelaskan bugnya

beri tahu saya jika judul perlu klarifikasi lebih lanjut.

semua masalah yang relevan telah ditutup dengan alasan bahwa itu telah diperbaiki di 6-canary (saya percaya tidak) atau dengan servis yang ditingkatkan (yang benar hanya dalam mungkin ekspor statis produksi).

Saya menulis ulang blog saya yang sudah ada ke next.js dan sebelumnya saya menggunakan garis miring. serve dapat membantu setelah saya membangun blog bertenaga next.js saya. Tetapi untuk memperbaiki dev env saya perlu menghilangkan garis miring dan menggunakan 301 Moved Permanently di prod; atau hidup dengan dukungan garis miring putus-putus di dev.

Untuk Mereproduksi

Berikut ini adalah kasus minimal yang dapat direproduksi (tautan ke repo repo ada di bawah cuplikan):

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

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

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

Repo minimal yang dapat direproduksi https://github.com/iamstarkov/next.js-trailing-slash-bug-demo

  1. kloning repo git clone https://github.com/iamstarkov/next.js-trailing-slash-bug-demo
  2. ubah direktori cd next.js-trailing-slash-bug-demo
  3. instal deps yarn
  4. jalankan dev: yarn dev
  5. buka http://localhost :3000/
  6. buka tab jaringan devtools
  7. amati http://localhost:3000/_next/static/development/pages/about.js menjadi 200ed
  8. amati http://localhost:3000/_next/on-demand-entries-ping?page=/about/ menjadi 200ed
  9. amati http://localhost:3000/about/ sedang 404ed
  10. amati upaya terus-menerus untuk menyelesaikan http://localhost:3000/about/
  11. amati di terminal Client pings, but there's no entry for page: /about/
  12. menyegarkan halaman
  13. amati 404 halaman.
  14. hapus garis miring di url atau klik http://localhost :3000/about
  15. amati halaman sedang 200ed
  16. untuk memastikan persistensi kesalahan ulangi langkah 5-15 sekali.

Perilaku yang diharapkan

  1. /about/ tidak boleh diselesaikan sebagai 404 not found
  2. /about/ harus diselesaikan sebagai 200 ok
  3. Server tidak boleh mencetak Client pings, but there's no entry for page: /about/
  4. keduanya /about dan /about/ harus bekerja dengan cara yang sama

Tangkapan layar

T/A

Sistem Informasi

  • OS: macOS High Sierra 10.13.6 (17G65)
  • Browser (seharusnya tidak masalah, tetapi dapat direproduksi di chrome 69.0.3497.100 dan safari Versi 12.0 (13606.2.11) (sama untuk safari 11)
  • Versi Next.js: 7.0.0 (bisa repro pada 5.x dan 6.x)

Konteks tambahan

Tambahkan konteks lain tentang masalah di sini.

Jika Anda mengubah kode ini di https://github.com/zeit/next.js/blob/459c1c13d054b37442126889077b7056269eeb35/server/on-demand-entry-handler.js#L242 -L249

atau node_modules/next/dist/server/on-demand-entry-handler.js secara lokal

          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}`

dan restart next dev dan buka http://localhost :3000/ dan klik tentang tautan lalu:

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

Saya pikir masalahnya (setidaknya sebagian) adalah ketidakmampuan middleware onDemandEntryHandler untuk menemukan halaman dalam entri jika halaman memiliki garis miring.

Saya harap penyelidikan dan persiapan saya selama 2 jam dapat membantu memperbaiki masalah ini.

story 8 feature request

Komentar yang paling membantu

Kami akan mendapatkan fitur untuk memperbaiki ini—sekitar satu hari!

Semua 119 komentar

masalah yang paling relevan dan penting adalah #1189 dan #3876

Menantikan ini akhirnya diselesaikan! @timneutkens Apa status masalah garis miring untuk 7 Berikutnya?

@NathanielHill saya bisa mereproduksinya di next@7

Saya menggunakan nextjs 7 dan trailing slash menghasilkan 404 untuk saya di dev dan prod:

  • pada pemuatan halaman awal
  • pada penyegaran halaman

Dan mempengaruhi:

  • tautan eksternal
  • tautan internal
  • URL ditempelkan ke browser

Cukup menghapus garis miring akan memperbaiki masalah.

Garis miring sering ditambahkan oleh browser, server, dan/atau layanan lain tempat tautan dapat ditempelkan, jadi meskipun saya dapat mengontrol tautan internal, sulit untuk mengontrol tautan apa yang mungkin akan diakses oleh pengguna eksternal

Saya juga melihat masalah ini di versi 7. Tidak yakin apakah ini relevan tetapi, saya membuat alias satu proyek Next.js ke subfolder dari penyebaran Now lainnya. Jadi url dasar kami adalah primer.style dan kami membuat alias aplikasi primer-components.now.sh Next.js kami menjadi primer.style/components . Pada produksi, halaman indeks primer.style/components berfungsi dengan baik, tetapi primer.style/components/ menghasilkan 404.

Saya harus mencari-cari sedikit untuk menemukan masalah ini. Saya menggunakan penyebaran statis di Netlify jadi itu bukan masalah pada prod, tetapi pada pengembangan (Berikutnya 7) kompilasi hanya membeku jika ada garis miring, dan sulit untuk mengetahui alasannya. Saya tidak berpikir ini (tidak menangani garis miring di lingkungan dev) adalah DX yang bagus.

Saya juga mengalami masalah ini dan itu sangat mengganggu, saya harap ini segera diperbaiki.

Jika Anda ingin trailing slash, Anda bisa melakukan ini. <Link href='/about' as='/about/'><a>about</a></Link> tetapi jika Anda menggunakan fridays/next-routes ini tidak mungkin. Jadi saya punya garpu di mana Anda dapat menambahkan trailingSlash sebagai penyangga. Semoga ini membantu

Jika Anda ingin trailing slash, Anda bisa melakukan ini. <Link href='/about' as='/about/'><a>about</a></Link> tetapi jika Anda menggunakan fridays/next-routes ini tidak mungkin. Jadi saya punya garpu di mana Anda dapat menambahkan trailingSlash sebagai penyangga. Semoga ini membantu

@aluminick Maaf, saya baru saja mencoba ini dan itu tidak berhasil untuk saya. Saya masih mendapatkan halaman traling-slashed (rilis terbaru), yang tidak ditemukan setelah penyegaran (perilaku saat ini).

juga tidak #6664 atau #6752 membantu dengan ini, karena experimental.exportTrailingSlash tidak membantu karena itu hanya untuk next export , saya percaya

ada permintaan tarik yang menjanjikan #6421 oleh @Janpot yang sayangnya tidak mencapai konsensus

@iamstarkov Apa status masalah ini? Adakah solusi selain kait server.js ?

Status @dryleaf : masih dibuka

Masalah serupa... redirect ketika beberapa garis miring ditambahkan. Contoh: https://github.com/zeit/next.js////////////issues/5214

Url GitHub tidak relevan

@iamstarkov Tidak yakin apa yang Anda maksud. Tapi setelah membaca ulang posting asli saya, sepertinya saya bisa lebih jelas.

Url GitHub dimaksudkan sebagai demonstrasi sederhana tentang cara kerja url (sebaiknya) saat aplikasi dibuat dengan Next.js. Dengan kata lain, jika pengguna menambahkan garis miring tambahan, url akan tetap berfungsi.

Adakah pembaruan untuk nextjs 9?

Saya baru mengenal Berikutnya, tetapi apa solusi yang Anda gunakan untuk masalah ini?

@iamstarkov Apa status masalah ini?

Saya terkejut bahwa masalah ini tidak diselesaikan dengan cara apa pun selama sekitar tahun!
Apakah tim Next.js memerlukan alasan lain untuk mulai memperbaiki ini?

URL harus berfungsi terlepas dari garis miring. Periksa situs mana pun di web.

Jika ini di luar cakupan Next.js, beri kami kemampuan untuk mengonfigurasinya di Now.
Saya benar-benar bingung bahwa tim Zeit mengabaikan masalah kritis seperti itu selama bertahun-tahun.

@exentrich Ini mudah dikonfigurasi di Zeit Now hanya dengan 301 mengarahkan semua garis miring ke rute yang sama tanpa garis miring:

now.json :

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

Namun, saya juga tidak mengerti mengapa ini tidak ditangani oleh Next.js sendiri dan mengapa tim mengabaikan masalah ini.

Ini, bersama dengan public/ (sedang dikerjakan) adalah masalah utama yang saya lihat dari konversi CRA.

@rauchg

@NathanielHill terima kasih!
Saya mencoba solusi ini, tetapi parameter kueri dihapus. Misalnya /some/?query=1 akan dialihkan ke /some tanpa permintaan. Apakah Anda tahu cara memperbaikinya?

Ya, itu terdengar seperti masalah @exentrich

Saya tidak akan menduga perilaku itu karena saya telah diberi tahu bahwa ada ^ implisit dan $ melilit regex (artinya contoh Anda tidak akan cocok). Mungkin ada cara untuk mengakses string kueri itu sendiri untuk menambahkannya kembali :man_shrugging: Semoga berhasil

Mencoba membuatnya bekerja menggunakan server ekspres khusus dan avinoamr/connect-slash tetapi tampaknya mengalami masalah yang sama

Ini tentu saja merupakan masalah besar terutama karena rute / membuang halaman Kesalahan dan itu merugikan SEO (yang merupakan salah satu daya tarik utama Berikutnya).

Pengalihan 301 dan server ekspres khusus semuanya tampaknya merupakan peretasan daripada perbaikan. Dalam kasus saya, saya memiliki aplikasi yang berfungsi penuh yang dibangun di Next tanpa server Express khusus - semuanya berfungsi dengan baik, tetapi sekarang saya harus membuat server Express baru hanya karena masalah garis miring. Upaya yang diperlukan tampaknya tidak proporsional mengingat ini adalah peretasan. Saya akan senang jika ini dapat diprioritaskan! Karena alasan ini, saya mendengar keluhan di tim saya tentang penggunaan Next sebagai lawan dari sesuatu seperti vanilla React/Angular dan itu tentu saja melemahkan kasus untuk Next.

PS: Saya sangat suka bekerja dengan Next ❤️

Ini tentu saja merupakan masalah besar terutama karena rute / membuang halaman Kesalahan dan itu merugikan SEO

Itu tidak merugikan SEO Anda. google memperlakukan garis miring sebagai halaman yang berbeda. Memilikinya 404 tidak memengaruhi SEO lebih dari halaman lain yang tidak ada di situs Anda. Selain itu, selama Anda tidak pernah menautkannya dengan garis miring, google tidak akan mencoba merayapinya sejak awal. Masalah ini, meskipun masih menjadi masalah yang valid, jauh lebih tidak kritis daripada yang Anda semua buat.

@nik-john @NathanielHill @dkrish @exentrich

Anda tidak perlu menggunakan server Express untuk melakukan 301 Redirect. Tergantung pada kebutuhan Anda, tetapi saya dapat memenuhi kebutuhan saya dengan server.js kustom.

Pengalihan 301 juga merupakan cara terbaik untuk SEO, karena Anda tidak akan mendapatkan penalti konten duplikat untuk rute slash dan non-slash.

Saya suka ❤️ Next.js, tetapi saya memilih ini untuk ditangani tanpa penyelesaian ini.

// 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

Itu tidak merugikan SEO Anda. google memperlakukan garis miring sebagai halaman yang berbeda. Memilikinya 404 tidak memengaruhi SEO lebih dari halaman lain yang tidak ada di situs Anda.

Saya mengerti maksud Anda bahwa itu tidak terlalu menyakiti SEO secara bawaan. Tapi itu memberi tekanan tambahan pada pengembang untuk mendapatkan definisi URL yang benar setiap saat, yang dapat menyebabkan kesalahan manusia. Pengembang yang baru mengenal Next tidak perlu tahu bahwa URL berikut (terlihat sangat normal) akan mengarah ke halaman 404. <Link href='/people/'>

Kerangka kerja yang matang seharusnya tidak tunduk pada kesalahan manusia seperti itu, idealnya.

Selain itu, selama Anda tidak pernah menautkannya dengan garis miring, google tidak akan mencoba merayapinya sejak awal.

Sekali lagi - ada masalah orang yang secara tidak sengaja menautkan ke _ www.mysite.com/people/_ alih-alih _ www.mysite.com/people_ (keduanya tampaknya persis sama untuk pengguna - bahkan sebagian besar pengembang).

Kedua skenario ini _dapat_ mempengaruhi SEO.

Sekarang, tidak mempertimbangkan dampak SEO, ada juga arti semantik dari URL - apa yang _dilakukan_ _ www.mysite.com/people / _ tunjuk? Idealnya karena menunjuk ke direktori, Next harus mengembalikan apa pun yang ada di pages > people > index.js (sebagai lawan dari pages > people.js untuk _www.mysite.com/people_) tetapi sebaliknya tidak mengembalikan apa pun, yang sangat cacat tingkat tinggi dalam cara kerja perutean.

Pustaka perutean utama sudah memiliki beberapa ketentuan untuk ini - seperti isExact dalam kasus React Router

Sementara saya mengerti dari mana Anda berasal, saya masih berpikir ini adalah masalah mencolok yang perlu ditingkatkan

Ini juga sama sekali tidak dapat dihindari dalam kasus next export

ada masalah orang yang secara tidak sengaja menautkan ...

Ada masalah orang yang secara tidak sengaja menautkan ke url yang tidak ada, mengapa /some/path/ menjadi kurang tidak ada daripada /some/path/dhgfiuwo ?

ada juga arti semantik dari URL

Ini sangat subjektif, sejauh yang saya tahu tidak ada spesifikasi di luar sana yang menentukan apa perbedaan semantiknya. Menurut spesifikasi URL , dengan dan tanpa garis miring dianggap sebagai url yang berbeda. Saya dapat memikirkan setidaknya 7 perilaku valid yang berbeda:

  • dengan dan tanpa memiliki konten yang sama sekali berbeda
  • dengan tidak 404, tanpa penyelesaian
  • dengan tekad, tanpa melakukan 404
  • dengan pengalihan ke tanpa
  • tanpa pengalihan ke dengan
  • dengan dan tanpa memiliki konten yang sama dengan penunjuk kanonik dengan
  • dengan dan tanpa memiliki konten yang sama dengan penunjuk kanonik ke tanpa

Pasangkan ini dengan kemungkinan memiliki /pages/some-page.js dan /pages/some-page/index.js (atau keduanya).

Haruskah next.js mendukung semua kasus penggunaan itu? Haruskah itu memilih perilaku default?

Saya tidak menentang ini, tetapi setelah mencoba menerapkan ini sebelumnya, saya hanya berpikir ada lebih banyak nuansa daripada yang terlihat pada awalnya.

Ada masalah orang yang secara tidak sengaja menautkan ke url yang tidak ada, mengapa/some/path/ kurang tidak ada daripada /some/path/dhgfiuwo?

Untuk kasus /some/path/dhgfiuwo - orang berharap rute dhgfiuwo bisa hilang. (Misalnya, pengguna dhgfiuwo tidak dapat ditemukan di sistem dan cara users/dhgfiuwo salah. Tidak adanya pengguna dalam sistem merupakan kejadian yang diharapkan.)
Untuk kasus /some/path/ - orang mengharapkan jalur ini sama dengan /some/path , karena ini adalah perilaku default di situs lain.
Oleh karena itu, kegagalan dalam would/some/path/ kurang tidak ada daripada /some/path/dhgfiuwo .

Saya melihat orang lain telah memposting solusi mereka, jadi saya ingin membagikan pendekatan saya: https://github.com/DevSpeak/next-trailingslash

Beberapa peningkatan dan dukungan untuk halaman yang dirutekan secara dinamis dalam hal ?= harus dilakukan IMO, tetapi ini hanya untuk menunjukkan ide.

Untuk solusi cepat, Anda dapat mengganti halaman _error default (seperti pada contoh @DevSpeak ).

@DevSpeak , saya akan merekomendasikan beberapa perubahan untuk repo Anda:

  • Hindari pengalihan 301 – mereka di- cache secara permanen oleh browser , dan dapat menyebabkan Anda sangat kesakitan. Dalam kebanyakan kasus, yang Anda butuhkan hanyalah 302.
  • Terner errorCode Anda dapat diperbarui (sudah usang dalam dokumen hingga minggu lalu)
  • Ini hanya sisi server, jadi Anda dapat membungkusnya dengan if (typeof window === 'undefined') { ... } untuk menggoyang pohon dari bundel klien

Inilah yang saya gunakan dalam proyek TypeScript (berdasarkan halaman kesalahan bawaan):

/pages/_error.tsx (atau hapus tipe TypeScript dan beri nama /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
  }
};

Catatan, ini juga mencatat kesalahan saat halaman dibuka, sehingga Anda dapat memeriksa log Anda untuk memperbaiki tautan/masalah lainnya.

@DevSpeak @bitjson Terima kasih atas saran Anda. Itu tentu saja salah satu cara untuk melakukan ini dan tentu saja memecahkan masalah dengan sangat baik. Tetapi mengingat _error.jsx awalnya dimaksudkan untuk menangani _errors_ dan bukan logika perutean rumah, menurut saya memiliki semua kode ini ada peretasan dan cukup deklaratif. Mengharapkan setiap pengguna untuk melakukan ini di setiap basis kode seharusnya tidak menjadi persyaratan - ini harus keluar dari kotak. = Saya berpendapat bahwa kondisi ini perlu dibangun dengan logika perutean, dengan opsi untuk memilih keluar seperti React Router.

@NathanielHill

Ini juga benar-benar tidak dapat dihindari dalam kasus ekspor berikutnya

Tunggu - Saya mengerti dari membaca dokumentasi bahwa ada kode khusus untuk menangani kondisi garis miring:

Halaman akan diekspor sebagai file html, yaitu /about akan menjadi /about.html.

Dimungkinkan untuk mengonfigurasi Next.js untuk mengekspor halaman sebagai file index.html dan memerlukan garis miring, yaitu /about menjadi /about/index.html dan dapat dirutekan melalui /about/. Ini adalah perilaku default sebelum Next.js 9. Anda dapat menggunakan next.config.js berikut untuk beralih kembali ke perilaku ini:

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

Bahkan jika ini bukan opsi untuk ekspor HTML statis melalui next export , saya tidak setuju dengan logika bahwa hanya karena Next mendukung fitur (luar biasa) ini, mode lain perlu menderita (saya tidak mengetahui statistik penggunaan tetapi saya akan menganggap lebih banyak orang menggunakan mode dengan-server biasa sebagai lawan dari tanpa server) terutama ketika ini telah dikenal sebagai kasus penggunaan yang umum

FYI: Ada RFC yang mungkin menarik bagi Anda https://github.com/zeit/next.js/issues/9081

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

@Janpot Suka - ini akan membawa kita setengah jalan yaitu memiliki semacam dukungan untuk pengalihan tanpa harus membuat server khusus. Ini masih penting karena untuk setiap rute yang ditambahkan pengguna, mereka harus mengatur pengalihan di next.config.js - atau mungkin kita bisa menggunakan regex untuk menangkap semua kasus seperti yang disebutkan @bitjson :

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

Dalam kedua kasus, jika tim inti memprioritaskan RFC ini, saya akan sangat menyarankan kita melangkah lebih jauh dan menjadikannya _config_ bawaan yang dapat _opt out_ seperti itu

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

Secara keseluruhan, saya pikir ini adalah langkah maju yang bagus - barang bagus @Timer!! 🔥

@nik-john Jalur yang saya tentukan di "/:path*/" Should catch all ( :path menangkap satu segmen, * membuatnya menangkap 0 hingga n instance.)

@Janpot Ah saya buruk Saya kira kita juga perlu mempertimbangkan parameter kueri tambahan di regex itu

Juga, saya masih mendukung bagian kedua:

Dalam kedua kasus tersebut, jika tim inti memprioritaskan RFC ini, saya akan sangat menyarankan agar kita melangkah lebih jauh dan menjadikannya sebagai konfigurasi bawaan yang dapat dipilih untuk tidak digunakan.

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

Jika Anda menggunakan server khusus dan ingin mengabaikan rute ketat, Anda juga dapat menggunakan pengendali rute khusus alih-alih membuat pengalihan.

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

Dengan cara ini kami dapat mendukung /path dan /path/ dan menyelesaikan ke halaman yang sama.

Penyedia federasi Oauth sering membutuhkan garis miring ke depan sehingga perilaku ini membuat alur sederhana menjadi sangat rumit. Apa tantangan teknis dalam menerapkan perilaku ini? Atau apakah ini keputusan desain selanjutnya?

Saya belum melihatnya disebutkan sejauh ini di utas ini, tetapi saya tidak mengalami masalah ini setelah penerapan dengan Now, saya hanya mengalaminya secara lokal saat menguji dengan 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();
  }
};

dapatkan ini dari stackoverflow dan bekerja dengan sempurna. solusi ini bekerja dengan express.

@GaneshKathar Saya tidak melihat bagaimana ini akan bekerja jika Anda memperhitungkan Next.js tidak menggunakan express

Saya pikir kita tidak bisa menyetujui ini dan itu harus dapat dikonfigurasi.

Saya sebenarnya ingin garis miring selalu, url relatif lebih mudah untuk dipikirkan ketika semua halaman diakhiri dengan garis miring.

Misalnya tidak masuk akal bahwa /about/index.tsx adalah /about bukannya /about/ , tetapi dapat dimengerti sekarang bahwa selanjutnya diharapkan tanpa garis miring. Jika semua halaman diakhiri dengan garis miring, itu akan memungkinkan halaman berisi subhalaman di masa mendatang, yang menurut saya cara yang lebih dapat diperluas untuk halaman.

Membuat tautan relatif di dalam file /about/index.tsx sekarang tidak praktis. Jika Anda membuat tautan ./mysubpage/ tautan tersebut mengarah ke root situs. Ini membuat subhalaman tidak dapat diganti namanya. Saya tidak dapat membuat direktori /about/ penuh dengan halaman yang bisa saya ganti namanya, karena saya harus pergi dan mengedit tautan relatif juga.

Juga situs wget -r menghasilkan hasil yang masuk akal dengan selalu mengikuti garis miring, menghasilkan file index.html.

Namun mengubah pengaturan ini secara besar-besaran melanggar perubahan karena semua situs mengharapkan garis miring yang tidak mengikuti, sehingga harus dapat dikonfigurasi.

Saya menggunakan versi 9 dan masalah ini masih belum terselesaikan

Saya dapat membuatnya berfungsi dengan menggunakan sesuatu seperti berikut di next.config.js :

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

  return paths;
},

Mengakses /authors memberikan 302 menunjuk location ke /authors/ . Saya menguji dengan http-serve , tidak yakin apakah perilaku ini ditentukan oleh server.

ketika saya menghadapi masalah ini, saya menemukan solusi ini

di halaman _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 };
}

apakah itu cara yang baik untuk mengatasi masalah tersebut?

Bagaimana dengan ini?

halaman/_app.jsx

```import React dari 'react';
impor Aplikasi dari 'berikutnya/aplikasi';

ekspor kelas default MyApp memperluas Aplikasi {
render() {
const { Komponen, 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 terima kasih atas sarannya. Itu membantu saya. Inilah cara saya menerapkannya untuk menjaga perilaku default untuk 404 non-trailing (yaitu saya hanya mengekspor ulang implementasi Error default):

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 };
};

ya itu akan dilakukan @cansin selama tidak ada lagi yang diputuskan :) bersorak!

Perbaikan kecil untuk solusi @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('/')) {

Satu-satunya perbedaan di sini adalah memeriksa apakah kode statusnya adalah 404. Saya mengalami masalah saat menggunakan Tautan untuk rute dinamis yang selalu dirender di server karena pengalihan. Jika Anda ingin perutean sisi klien berfungsi, Anda tidak dapat menambahkan garis miring ke prop Tautan href , tetapi Anda perlu memastikan bahwa Anda tidak mengarahkan ulang dalam kasus ini.

Masalah dengan menerapkan solusi dalam komponen Kesalahan adalah bahwa hal itu akan menimbulkan kesalahan pemberitahuan dalam pengembangan yang mengganggu saya. Beberapa peningkatan pada pengalihan sisi klien saya sebelumnya:

Apa yang ditingkatkan adalah sekarang ia menggunakan next/router di sisi klien dan penggantian url terjadi tanpa memuat ulang.

halaman/_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} />;
  }
}

juga terima kasih kepada @mrowne untuk perbaikan 404 :)

Mengambil solusi @cansin dan menambahkan kemampuan untuk menangani parameter kueri

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 dapatkah Anda memberikan contoh url dengan garis miring dan parameter kueri terjadi secara bersamaan? Apakah Anda berpikir sejalan dengan /blog/?123 ?

Terima kasih semuanya atas beberapa solusi Anda di atas. Mereka bekerja!

Namun, apakah kami memiliki cara resmi untuk memperbaiki masalah ini dari tim Next? Masalah ini telah ada di sini selama bertahun-tahun.

Halaman direktori tidak disajikan dengan garis miring di ekspor berikutnya

@pinpointcoder dapatkah Anda memberikan contoh url dengan garis miring dan parameter kueri terjadi secara bersamaan? Apakah Anda berpikir sejalan dengan /blog/?123 ?

@coodoo Bukan dia, tapi ya, sayangnya ini sering terjadi. Saat ini saya sedang dalam proses memigrasikan situs WordPress secara bertahap ke Next.js, dan untuk beberapa alasan, "pengembang" asli memutuskan untuk memaksakan garis miring di setiap URL, jadi saat ini kami memiliki banyak permintaan dengan keduanya slash DAN parameter kueri.

Saat kami akan memigrasikan banyak posting blog yang URL kanoniknya saat ini menyertakan garis miring, ini sangat merepotkan saya sekarang.

Saya memutuskan untuk menerapkan server khusus untuk menangani ini dan ternyata itu mudah dilakukan, dan Anda masih dapat menggunakan sistem perutean berbasis file next.js. Dengan begitu Anda dapat menulis ulang URL yang dilihat next.js dan URL asli masih memiliki garis miring di bagian akhir:

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}`)
    })
})

Lihat https://nextjs.org/docs/advanced-features/custom-server

@mbrowne Kami sebenarnya memiliki banyak alasan untuk menggunakan server khusus, tetapi hal utama yang mencegah saya menerapkannya sejauh ini adalah kenyataan bahwa Anda kehilangan Pengoptimalan Statis Otomatis. Apakah Anda tahu apakah mungkin untuk menentukan rute statis secara manual?

Kami tidak memerlukan pengoptimalan statis otomatis untuk aplikasi kami saat ini, jadi saya belum memeriksanya.

Saya juga menggunakan server khusus tetapi ketika Anda meneruskan url yang dimodifikasi (tanpa garis miring) ke handle , SSR melihat url yang berbeda dari sisi klien.
Saya lebih suka router next untuk mencocokkan url dengan garis miring tanpa peretasan jahat itu.

2020 dan bug ini masih terjadi. Sulit dipercaya

Ini adalah bug buruk yang benar-benar perlu diperbaiki. /products berfungsi, tetapi /products/ tidak. Dengan tautan ini

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

saya mendapat

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

Namun, jika saya mengarahkan tautan ke /products/ , mengunjungi tautan, dan menyegarkan halaman selama pengembangan, saya mendapatkan 404. Ini adalah pengalaman pengembangan yang cukup menyakitkan.

Masalah ini pertama kali dilaporkan 1,5 tahun yang lalu; bisakah kita mendapatkan perbaikan resmi? Itu masih ada di 9.3.4.

Saya membuat pengalihan ke url slash non-trailing alih-alih menampilkan konten, karena alasan SEO.

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}`)
  })
})

Untuk SEO, rel="canonical" dapat membantu, tetapi masih perlu memperbaiki masalah 404 ini.

Ini adalah bug buruk yang benar-benar perlu diperbaiki. /products berfungsi, tetapi /products/ tidak. Dengan tautan ini

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

saya mendapat

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

Namun, jika saya mengarahkan tautan ke /products/ , mengunjungi tautan, dan menyegarkan halaman selama pengembangan, saya mendapatkan 404. Ini adalah pengalaman pengembangan yang cukup menyakitkan.

Masalah ini pertama kali dilaporkan 1,5 tahun yang lalu; bisakah kita mendapatkan perbaikan resmi? Itu masih ada di 9.3.4.

Saya juga saat ini mendapatkan masalah ini.

Inilah cara saya memperbaikinya, https://medium.com/@thisisayush/handling -404-trailing-slash-error-in-nextjs-f8844545afe3

Inilah cara saya memperbaikinya, https://medium.com/@thisisayush/handling -404-trailing-slash-error-in-nextjs-f8844545afe3

Terima kasih, meskipun ini memerlukan server khusus saat mengembangkan secara lokal, dan seharusnya tidak diperlukan.

@timneutkens Adakah kemungkinan perbaikan untuk masalah ini dapat dikerjakan ke dalam jadwal pengembangan?

Lebih penting lagi, solusi pengalihan tidak berfungsi untuk mereka yang memelihara situs yang areanya sudah disiapkan untuk menambahkan garis miring daripada menghapusnya dalam produksi. Saya tidak berpikir kerangka kerja harus mendikte pilihan ini secara sewenang-wenang.

@AlexSapoznikov 's solusi bekerja dengan baik bagi kita dengan Netlify (yang menambahkan garis miring secara default). Berikut adalah versi lanjutan yang menambahkan dukungan untuk parameter kueri:

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} />;
  }
}

Saya minta maaf karena saya seorang pemula JS Berikutnya, meskipun saya memiliki pengalaman pengembangan perangkat lunak di SDK dan platform lain.

Saya pikir "bug" ini paling mengejutkan saya. Bagi saya, itu melanggar "prinsip paling tidak heran". Saya hanya berharap /about/ dan /about saya berfungsi sama, karena saya menempatkan index.tsx ke folder /pages/about/ saya.

Saya pertama kali mulai membuat situs web pada akhir 1990-an dengan HTML FTP ke server saya, dan kemudian pindah ke PHP & Apache, dan akhirnya server Java. Sekarang saya mengkhususkan diri dalam aplikasi seluler. Rasanya aneh bagi saya bahwa perilaku ini bukan default, dan saya harus menulis halaman server khusus untuk memperbaikinya di server dev saya.

Saya berencana untuk melakukan ekspor statis, sehingga tidak akan muncul dalam produksi bahkan jika saya tidak menulis server kustom. Itu memang membuat dev dan debugging sedikit lebih menyebalkan.

Bisakah kita mendapatkan tanda "pengembang berikutnya" yang memperbaikinya sehingga pengembang yang malas tidak perlu menulis logika perutean tambahan hanya untuk waktu dev/debug?

Terima kasih!

ps: Ya, saya tahu bahwa /about dan /about/ adalah URL yang sama sekali berbeda. Aku baru saja benar-benar bingung ketika saya menempatkan index.tsx file di saya /pages/about/ folder, dan menemukan bahwa hanya bekerja dengan /about path tetapi tidak bekerja dengan /about/ . Saya tidak akan terlalu terkejut jika sebaliknya.

pps: Sangat membingungkan ketika saya memiliki komponen <Link></Link> yang menunjuk ke /about/ dan berfungsi seperti yang diharapkan. Kemudian ketika saya menekan refresh di browser saya, itu langsung 404s, meskipun URL tidak berubah. Itu sangat mengejutkan. :-D

Tapi tunggu, itu semakin buruk! Kami menambahkan fungsi checkForTrailingSlash kustom di dalam _error.js yang akan menghapus garis miring dan pengalihan. Ini berfungsi dengan baik untuk sementara waktu sampai kami (akhirnya) menambahkan halaman 404 khusus dan menemukan bahwa dengan halaman 404 khusus, Next.js sepenuhnya melewati Error . Ini berarti tidak ada logika khusus Anda di dalam Error.getInitialProps akan berfungsi lagi - termasuk pemeriksaan untuk garis miring tambahan.

Kira saya akan mencoba solusi _app.js disebutkan orang lain, karena server khusus belum memungkinkan.

@AlexSapoznikov 's solusi bekerja dengan baik bagi kita dengan Netlify (yang menambahkan garis miring secara default). Berikut adalah versi lanjutan yang menambahkan dukungan untuk parameter kueri:

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} />;
  }
}

Ada kesalahan kritis dalam contoh kode Anda: permintaan ke rute indeks dengan parameter kueri akan menimbulkan kesalahan, karena Anda akhirnya mencoba meneruskan hanya string kueri ke Next.js sebagai asPath .

Ini memperbaikinya:

  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;
      }
    }
  }

Untuk membuat karya ini dengan SSR aku harus menambahkan berikut ke @pjaws & solusi @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)
        : {},
    };
  }

Mungkin ide yang baik untuk menggeneralisasi fungsi ini menjadi fungsi yang berfungsi baik selama SSR dan selama CSR dan menyebutnya di kedua tempat ( getInitialProps dan render ).

oleh

ini akan memperbaiki tetapi judulnya salah. Hmm
image

@AlexSapoznikov @pjaws

Solusi Anda menempatkan kami dalam lingkaran tak terbatas:

  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;
      }
    }
  }

Konteks

Karena alasan di luar kendali kami, kami harus menggunakan opsi exportTrailingSlash di next.config.js .

Kami ingin memiliki tautan ke halaman lain tetapi kami ingin tautannya menjadi /somepage?param=whatever .

Tampaknya tautan berikutnya mengonversi ini menjadi /somepage/?param=whatever dan kami mendapatkan halaman tidak ditemukan.

Menggunakan solusi di atas menyelesaikan masalah params, tetapi kemudian ketika membuka halaman yang digunakan seperti /somepage/ ia memasuki loop tak terbatas.

Saya pikir @ronyeh telah membuat poin yang sangat bagus di sini, jadi saya benar-benar menginginkan solusi resmi untuk masalah ini :(

Untuk membuat karya ini dengan SSR aku harus menambahkan berikut ke @pjaws & solusi @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)
        : {},
    };
  }

Mungkin ide yang baik untuk menggeneralisasi fungsi ini menjadi fungsi yang berfungsi baik selama SSR dan selama CSR dan menyebutnya di kedua tempat ( getInitialProps dan render ).

Ini berfungsi untuk halaman dengan getServerSideProps dan sekarang url dengan garis miring mengembalikan halaman yang sama tanpa 404.
Tetapi ada satu kesalahan, saya memiliki beberapa halaman yang menggunakan rute dinamis dan getStaticPaths, saya tidak dapat menggunakan getServerSideProps ke dalamnya dan dengan demikian ketika rute dinamis ini dijelajahi dengan garis miring, mereka pertama-tama mengembalikan 404 dan kemudian mengarahkan ulang ke halaman .

Saya bekerja dengan folder /api/test

  • halaman/api/test.tsx
  • halaman/api/test/[id].tsx

itu bekerja untuk

  • DAPATKAN /api/tes
  • DAPATKAN /api/test/123
  • DAPATKAN /api/test/123/

dan saya baru tahu bahwa ini tidak berhasil

  • DAPATKAN /api/tes/

tidak yakin apakah ini masalah terkait
P/D exportTrailingSlash = true tidak menyelesaikannya

Ini adalah masalah yang sangat lama, apakah ada alasan mengapa tidak ditangani begitu lama?

Saya tidak yakin apa yang tidak berfungsi lagi.

Sekedar informasi, persyaratannya adalah sebagai berikut:

| | exportTrailingSlash: false | exportTrailingSlash: benar |
|-------------------------|----------------------- -----|-----------------------||
| url diakhiri dengan / | Seharusnya tidak bekerja | Harus bekerja |
| url tidak diakhiri dengan / | Harus bekerja | Seharusnya tidak bekerja |

Ini berfungsi seperti yang diharapkan di mana:

  • Secara lokal kami menggunakan exportTrailingSlash: false
  • Untuk penerapan (pembuatan produksi) kami menggunakan exportTrailingSlash: true dan nginx mengonversi url/ menjadi url/index.html

Dari apa yang saya lihat di @andrescabana86 Ini berfungsi di tempat yang seharusnya tidak: GET /api/test/123/ sedangkan GET /api/test/ tidak berfungsi dan seharusnya tidak.

@Izhaki saya mencoba keduanya, menggunakan prod... dan bagi saya tidak berfungsi

  • DAPATKAN /api/tes/

dan saya menggunakan exportTrailingSlash: true

Saya dapat mencoba membuat repo publik jika Anda mau, mungkin saya lupa sesuatu di tengah.

terima kasih atas jawaban Anda

@andrescabana86 Saya tidak yakin berapa banyak repo publik akan membantu di sini - ini mungkin beberapa konfigurasi di server yang Anda gunakan.

Kami sedang menguji build produksi kami (dengan exportTrailingSlash: true ) secara lokal menggunakan skrip ini di package.json :

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

Tolong beri tahu saya jika masuk ke browser Anda ke http://localhost:5000/api/test/ berhasil.

(Perhatikan bahwa $(pwd) ada di Mac/Linux - lihat ini untuk windows)

@Izhaki masalahnya adalah tentang fakta bahwa (seperti yang disarankan oleh laporan awal) "garis miring di tautan untuk halaman yang sah berfungsi untuk navigasi sisi klien tetapi mengarah ke bundel yang tidak ditemukan dan 404 pada penyegaran keras (ssr)". Jadi ada ketidakcocokan antara perilaku perubahan rute sisi klien, versus penyegaran keras. Saya tidak yakin apakah masalah berlanjut dengan versi terbaru Next.js. Saya dapat melaporkan kembali ke sini setelah saya mengujinya.

Baru saja diuji dengan 9.4.1 dan exportTrailingSlash: true .

Pergi ke http://localhost:6500/admin/ mengembalikan 404 saat mengembangkan secara lokal.

Tetapi jalur yang sama berfungsi saat Anda mengekspor.

Perhatikan bahwa exportTrailingSlash mengisyaratkan bahwa ini hanya untuk _ekspor_.

Yang kami lakukan adalah menggunakan:

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

Itu berarti segala sesuatunya berfungsi sebagaimana dimaksud ketika kami mengembangkan secara lokal. Dan berfungsi dengan baik saat digunakan (melalui ekspor).

Bukankah itu solusi yang tepat dan layak untuk ini?

Jika URL tidak berfungsi pada pengembangan tetapi berfungsi pada produksi, tidakkah menurut Anda itu bertentangan dengan prinsip yang paling tidak mengejutkan? Saya pikir ini masih harus dianggap sebagai bug.

^ Yang mengatakan, saya cukup yakin sebelumnya pada produksi ada perilaku yang bertentangan antara refresh halaman vs acara router.push. Saya tidak tahu apakah itu masih terjadi.

@andrescabana86 @Izhaki exportTrailingSlash tidak terkait dengan ini. Opsi itu terkait dengan pengeksporan statis aplikasi Next.js. Ketika benar, example/index.html dihasilkan, sedangkan ketika salah, example.html dihasilkan. Pemahaman saya adalah bahwa exportTrailingSlash tidak ada hubungannya dengan mode pengembangan.

Saya pikir salah satu sumber kebingungan adalah ketika Anda memiliki exportTrailingSlash next.js menambahkan garis miring ke tautan. Ini terjadi dalam pengembangan juga, saya tidak yakin harus melakukan ini? Tapi bagaimanapun, ini bukan hanya tentang example/index.html vs example.html - Anda juga perlu mengubah tautan.

Jika URL tidak berfungsi pada pengembangan tetapi berfungsi pada produksi, tidakkah menurut Anda itu bertentangan dengan prinsip yang paling tidak mengejutkan? Saya pikir ini masih harus dianggap sebagai bug.

Saya mungkin salah, tetapi opsi exportTrailingSlash adalah untuk server nginx yang tidak dikonfigurasi untuk melayani /something.html ketika urlnya adalah /something .

Ini tidak terjadi dengan server berikutnya yang digunakan untuk pengembang lokal. Jadi apa yang berhasil dan apa yang tidak bergantung pada apa yang melayani aplikasi Anda.

Anda dapat membuat kasus bahwa ketika exportTrailingSlash benar, server berikutnya harus mendukung rute yang diakhiri dengan garis miring (walaupun ini akan membuat export dalam exportTrailingSlash agak tidak relevan).

FWIW ini sedang dikerjakan #13333

Saya bukan pembuat kode yang sangat berpengalaman, menggunakan Next.js terutama untuk pendaratan multi-halaman. Rupanya, saya telah menggunakan solusi berikut hampir sepanjang waktu, tanpa sepengetahuan efeknya. Berikut versi yang dipreteli:

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

Dalam kasus saya kodenya sedikit lebih rumit, karena saya menggunakannya untuk mendukung prefiks url statis tambahan, dll. Tetapi versi yang dipreteli ini tampaknya berfungsi untuk masalah yang dibahas dengan baik, terlepas dari exportTrailingSlash pengaturan dan efeknya pada Link s. Misalnya URL /about dan /about/ berfungsi dengan baik.

Dalam bentuk sekarang Ini pada dasarnya meniru perutean asli Next.js. Kelemahannya: memerlukan server.js , dan Anda harus mendukungnya secara manual untuk URL "lebih dalam" (dengan "subfolder" tambahan), misalnya /company/about/ . Tetapi tampaknya ini merupakan solusi yang relatif sederhana bagi mereka yang sudah menggunakan server.js kustom dalam proyek mereka.

Untuk membuat karya ini dengan SSR aku harus menambahkan berikut ke @pjaws & solusi @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)
        : {},
    };
  }

Mungkin ide yang baik untuk menggeneralisasi fungsi ini menjadi fungsi yang berfungsi baik selama SSR dan selama CSR dan menyebutnya di kedua tempat ( getInitialProps dan render ).

Ini berfungsi untuk halaman dengan getServerSideProps dan sekarang url dengan garis miring mengembalikan halaman yang sama tanpa 404.
Tetapi ada satu kesalahan, saya memiliki beberapa halaman yang menggunakan rute dinamis dan getStaticPaths, saya tidak dapat menggunakan getServerSideProps ke dalamnya dan dengan demikian ketika rute dinamis ini dijelajahi dengan garis miring, mereka pertama-tama mengembalikan 404 dan kemudian mengarahkan ulang ke halaman .

@gauravkrp Ini sebenarnya adalah tambahan yang sangat penting, karena solusi @AlexSapoznikov sebenarnya masih akan mengembalikan 404 untuk halaman tersebut ke Google (karena pengalihan terjadi pada klien). Saya membayangkan SEO adalah alasan utama banyak dari kita menggunakan Next.js di tempat pertama.

Saya juga berpikir bahwa memasukkan ini ke dalam getInitialProps seharusnya hanya berfungsi, dan bagian di dalam fungsi utama tidak diperlukan pada saat ini. Peringatan utama di sini adalah bahwa Anda kehilangan Pengoptimalan Statis Otomatis dengan memiliki ini - mungkin lebih baik daripada sekelompok 404.

Untuk beberapa berbagi...

Proyek saya adalah Express + Next.js .
express 4.17.1
next 9.4.5-canary.7

Saat pengembangan

Waktu Proses Dinamis

// 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));

Kapan Produksi

Ekspor Statis
Jalankan next build dan next 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/
});

Kesimpulannya

Saya tidak memiliki masalah saat mengarahkan ulang dengan mengklik aplikasi klien,
juga penyegaran keras bekerja pada static route .

Tapi itu akan 404 ketika hard refresh pada dynamic route ,
seperti /album/[id].jsx atau /album/123 ,
Jadi saya berharap untuk memperbaiki masalah ini dengan menggunakan mekanisme berikut.

misalnya
Ketika mencapai 404 pada /album/123 ,
server harus terus menyediakan konten html,
browser akan terus memuat halaman tanpa masalah,
ketika Next.js boot maka next/router akan menanganinya secara otomatis.

apakah ada solusi sementara untuk masalah ini pada produksi?

Kami akan mendapatkan fitur untuk memperbaiki ini—sekitar satu hari!

apakah ada solusi sementara untuk masalah ini pada produksi?

Ada banyak di utas ini, tetapi saat ini saya menggunakan apa yang diposting @gauravkrp baru-baru ini, dan itu berfungsi dengan baik untuk saya.

Anda dapat melacak PR di sini: #13333

Ini sekarang telah diselesaikan di next@^9.4.5-canary.17 !

Berapa lama waktu yang dibutuhkan untuk fitur dari canary ke master?

Ini sekarang telah diselesaikan di next@^9.4.5-canary.17 !

Dan bagaimana tepatnya itu diselesaikan? hanya menghapus garis miring? jika saya mengakses " www.site.com/help/ " saya dialihkan ke: " www.site.com/help " , dapatkah kami memiliki opsi di sana kami memilih untuk meninggalkan garis miring? mengakses " www.site.com/help/ " atau " www.site.com/help " akan meninggalkan atau mengalihkan atau menambahkan "/" di akhir untuk memiliki: " www.site.com/help/ "

@Valnexus lihat #13333, ini termasuk opsi eksperimental:

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

Berapa lama waktu yang dibutuhkan untuk fitur dari canary ke master?

Ketika sudah siap. Masih ada kasus edge dalam penanganan yang sedang diselesaikan. Setelah itu diperbaiki, itu bisa menjadi stabil.

@timneutkens @Janpot

Saya mencoba canary terbaru berikutnya (9.4.5-canary.27) tetapi ketika saya membuat halaman test dan saya mengakses www.example/test/ itu dialihkan ke www.example/test
Saya pikir perilaku untuk kedua kasus harus sama.

Saat mengakses www.example/test/ itu harus tetap di www.example/test/ .
Saat mengakses www.example/test itu harus tetap di www.example/test .
Saya mengujinya di Nuxt.js, ia bekerja dengan perilaku yang sama yang saya jelaskan di atas.

Saya pikir perilaku untuk kedua kasus harus sama.

Alasan pengalihan adalah untuk memastikan mesin telusur tidak melihat konten duplikat. Apa kasus penggunaan Anda yang sebenarnya?

Saya tidak mengerti mengapa ini merupakan masalah tertutup jika belum digabungkan ke rilis stabil. Jika saya mengerti dengan benar itu hanya diperbaiki dalam rilis kenari untuk saat ini, kan?

Masalah ditutup saat permintaan tarik terkait mendarat, karena tersedia untuk segera digunakan di canary. Jika Anda membutuhkan fitur ini, silakan tingkatkan ke saluran kenari.

Kedengarannya bagus. Terima kasih, @Timer!

@Janpot saya melihat https://github.com/issues/ dan https://github.com/issues dapat mengakses perilaku yang sama tanpa pengalihan.

https://twitter.com/explore/ dan https://twitter.com/explore , yang ini juga.

Jika ada masalah dengan mesin pencari, Mengapa Github dan Twitter tidak memperbaikinya?
Saya pikir ini adalah perilaku default untuk situs web apa pun.

Tidak ada kasus penggunaan khusus, hanya pendapat saya bahwa itu harus bekerja seperti itu.

Jika ada masalah dengan mesin pencari, Mengapa Github dan Twitter tidak memperbaikinya?

@armspkt Tidak masalah karena ada beberapa cara untuk menyelesaikannya. Misalnya Twitter menggunakan atribut <link rel="canonical"> untuk memberi tahu bot pencarian halaman mana yang harus mereka jelajahi dan versi lain harus ditandai sebagai duplikat.

Jadi redirect adalah cara yang layak untuk membuat SEO di situs web Anda. Anda dapat membaca info lebih lanjut di sini .

@ziserman Jika kita memiliki beberapa cara untuk menyelesaikannya, kita harus menjaga url yang sama tanpa redirect untuk pengalaman pengguna.

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

Nuxtjs memiliki beberapa opsi untuk dipilih (tidak terdefinisi, benar, salah)

Haruskah Nextjs memiliki opsi server untuk dipilih juga?

Alasan pengalihan adalah untuk memastikan mesin telusur tidak melihat konten duplikat. Apa kasus penggunaan Anda yang sebenarnya?

@Janpot API kami memiliki garis miring di banyak tempat. Rilis terbaru memunculkan banyak 404 di backend karena Url dengan garis miring (/api/test/ -> /api/test) tidak cocok

Saya tidak tahu apakah itu akan berhasil untuk semua orang, tetapi saya telah menemukan solusi ini yang cocok untuk saya. Masukkan ke dalam file _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 Saya telah meminimalkan komentar Anda karena menyebabkan kemunduran kinerja yang parah di aplikasi Next.js.

Versi next@canary terbaru memperbaiki bug ini, harap tingkatkan sebagai gantinya!

@mlbonniec Saya telah meminimalkan komentar Anda karena menyebabkan kemunduran kinerja yang parah di aplikasi Next.js.

Versi next@canary terbaru memperbaiki bug ini, harap tingkatkan sebagai gantinya!

Tidak masalah!
Namun, saya memperbarui sebelumnya, dan itu tidak menyelesaikan masalah.
Dengan npm update

Jika kenari Next.js terbaru tidak memperbaiki bug untuk Anda, silakan buka masalah baru agar kami dapat memeriksanya. 🙏

Pertanyaan singkat, bagaimana proyek dengan next export menangani perubahan ini? Dengan membuat halaman yang sama sekali baru untuk setiap halaman untuk garis miring? Saya tidak berpikir aplikasi yang diekspor dapat menentukan pengalihan HTTP (atau penulisan ulang).

Proyek yang menggunakan next export akan memiliki semua <Link /> di sisi klien diperbarui dengan benar, tetapi pengalihan sisi server akan memerlukan konfigurasi manual. Proyek yang disebarkan dengan target tanpa server atau next start akan mengonfigurasi pengaturan ini secara otomatis.

@Timer setelah ini mencapai rilis penuh, apakah kita masih perlu menggunakan opsi eksperimental?

@Timer setelah ini mencapai rilis penuh, apakah kita masih perlu menggunakan opsi eksperimental?

Tidak, hanya akan tersedia apa adanya.

Saya kira opsi trailingSlash tidak akan berfungsi untuk next export ? Apa cara terbaik untuk mengarahkan /page/ ke /page (atau sebaliknya), katakanlah, halaman github?

Saya kira opsi trailingSlash tidak akan berfungsi untuk next export ? Apa cara terbaik untuk mengarahkan /page/ ke /page (atau sebaliknya), katakanlah, halaman github?

Sejauh yang saya ketahui, halaman github tidak memiliki fitur pengalihan. Ini berhasil di luar kotak di vercel.com yang juga gratis untuk proyek hobi (seperti halaman github).

Proyek yang menggunakan next export akan memiliki semua <Link /> di sisi klien diperbarui dengan benar, tetapi pengalihan sisi server akan memerlukan konfigurasi manual. Proyek yang disebarkan dengan target tanpa server atau next start akan mengonfigurasi pengaturan ini secara otomatis.

Hai @Timer Bisakah Anda menjelaskan lebih lanjut? Bagaimana saya bisa mengonfigurasi secara manual? Jadi inilah situasi saya. Di situs web saya, saya menggunakan next-i18next . Setelah saya menggunakan next build && next export , semua tautan internal berfungsi tetapi ketika memasukkan URL secara manual, TIDAK ADA yang berfungsi dan menyebabkan kesalahan 404. Dari sini saya memutuskan untuk menggunakan trailingSlash:true dan memasukkan /pricing secara manual akan berfungsi sekarang tetapi /zh/pricing menyebabkan 404 kesalahan.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat