Next.js: تعمل الشرطة المائلة اللاحقة في الرابط للصفحة الشرعية على التنقل من جانب العميل ولكنها تؤدي إلى عدم العثور على الحزمة و 404 عند التحديث الثابت (ssr)

تم إنشاؤها على ٢٠ سبتمبر ٢٠١٨  ·  119تعليقات  ·  مصدر: vercel/next.js

تعمل الشرطة المائلة اللاحقة في الرابط للصفحة الشرعية على التنقل من جانب العميل ولكنها تؤدي إلى عدم العثور على الحزمة و 404 عند التحديث الثابت (ssr)

تقرير الشوائب

صف الخلل

اسمحوا لي أن أعرف إذا كان العنوان يحتاج إلى مزيد من التوضيح.

تم إغلاق جميع المشكلات ذات الصلة بحجة أنه تم إصلاحها في 6-canary (أعتقد أنها ليست كذلك) أو عن طريق تحسين الخدمة (وهذا صحيح فقط ربما في تصدير ثابت للإنتاج).

أنا أعيد كتابة مدونتي الحالية إلى next.js واستخدمت سابقًا شرطة مائلة. أحدث serve يمكن أن يساعد في ذلك بمجرد أن أنشيء مدونتي next.js المدعومة. ولكن من أجل إصلاح بيئة التطوير ، فأنا بحاجة إما إلى التخلص من الخطوط المائلة اللاحقة واستخدام 301 Moved Permanently في المنتج ؛ أو العيش مع الدعم المائل المائل المكسور في dev.

لإعادة إنتاج

في ما يلي الحد الأدنى من الحالات القابلة لإعادة الإنتاج (يوجد رابط إلى Repro أسفل المقتطف):

// 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. تشغيل dev: 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)
  • المستعرض (لا يجب أن يكون مهمًا ، ولكن يمكن إعادة صياغته في الكروم 69.0.3497.100 وإصدار Safari 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
    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 على إيجاد صفحة في الإدخالات إذا كانت الصفحة تحتوي على شرطة مائلة.

آمل أن تساعد ساعتان من التحقيق والتحضير في حل هذه المشكلة.

story 8 feature request

التعليق الأكثر فائدة

نحن على وشك الحصول على ميزة لإصلاح هذا — يوم أو نحو ذلك!

ال 119 كومينتر

القضايا الأكثر صلة وأبرزها هي # 1189 و # 3876

نتطلع إلى حل هذا في النهاية! timneutkens ما هي حالة مشاكل

NathanielHill يمكنني إعادة إنتاجه في اليوم التالي @ 7

أنا أستخدم nextjs 7 والشرطة المائلة اللاحقة تنتج لي 404 في كل من dev و prod:

  • عند تحميل الصفحة الأولى
  • في تحديث الصفحة

ويؤثر على:

  • ارتباط خارجي
  • ارتباط داخلي
  • عنوان 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 ، لذا فهي ليست مشكلة في المنتج ، ولكن في التطوير (التالي 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 فقط ، على ما أعتقد

كان هناك طلب سحب واعد # 6421 من Janpot والذي لم يتوصل إلى أي إجماع ، لسوء الحظ

iamstarkov ما هو وضع هذه القضية؟ هل توجد أي حلول بجانب الخطاف server.js ؟

وضع dryleaf : لا يزال مفتوحًا

مشكلة مماثلة ... إعادة التوجيه عند إضافة عدة شرطات مائلة للأمام. مثال: https://github.com/zeit/next.js////////////issues/5214

عناوين URL لـ GitHub ليست ذات صلة

iamstarkov لست متأكدًا مما

يُقصد من عنوان url الخاص بـ GitHub أن يكون عرضًا بسيطًا لكيفية عمل عناوين url (ويفضل) عند إنشاء تطبيق باستخدام Next.js. بمعنى آخر ، إذا أضاف المستخدم شرطة مائلة إضافية ، فيجب أن يظل عنوان url يعمل.

أي تحديث ل nextjs 9؟

أنا جديد في Next ولكن ما هو الحل البديل الذي يستخدمه الناس لهذه المشكلة؟

iamstarkov ما هو وضع هذه القضية؟

لقد صدمت لأن هذه المشكلة لم تحل بأي شكل من الأشكال لمدة عام تقريبًا!
هل يحتاج فريق Next.js إلى أي أسباب أخرى لبدء إصلاح هذا؟

يجب أن تعمل عناوين URL بغض النظر عن الشرطة المائلة اللاحقة. تحقق من أي موقع على شبكة الإنترنت.

إذا كان هذا خارج نطاق Next.js ، فامنحنا القدرة على تكوين هذا في الآن.
أنا في حيرة من أمري أن فريق Zeit يتجاهل مثل هذه القضايا الحرجة لسنوات.

exentrich يمكن تكوين هذا بسهولة في Zeit Now ببساطة عن طريق إعادة توجيه كل الخطوط المائلة

now.json :

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

ومع ذلك ، لا أفهم أيضًا سبب عدم معالجة Next.js لهذه المشكلة ولماذا تجاهل الفريق هذه المشكلة.

هذا ، جنبًا إلى جنب مع public/ (في الأعمال) هي المشكلات الرئيسية التي أرى تحويل CRA إليها.

تضمين التغريدة

تضمين التغريدة
لقد جربت هذا الحل ، ولكن تم تجريد معلمات الاستعلام. على سبيل المثال ، سيتم إعادة توجيه /some/?query=1 إلى /some بدون استعلام. هل تعرف كيفية اصلاحها؟

نعم ، هذا يبدو وكأنه مشكلة exentrich

لم أكن لأخمن هذا السلوك كما قيل لي أن هناك ^ و $ ضمنيًا ملفوفًا حول regex (بمعنى أن المثال الخاص بك لن يتطابق). ربما هناك طريقة للوصول إلى سلسلة الاستعلام الخاصة بها لإضافتها مرة أخرى: man_shrugging: حظ سعيد

محاولة تشغيله باستخدام خادم سريع مخصص و avinoamr / connect-slash ولكن يبدو أنه يواجه نفس المشكلة

هذه بالتأكيد مشكلة كبيرة خاصةً لأن مسارات / تطرح صفحات خطأ وهذا يؤذي مُحسّنات محرّكات البحث (وهو أحد السحوبات الأساسية لـ Next).

يبدو أن عمليات إعادة التوجيه 301 والخوادم السريعة المخصصة جميعها عمليات قرصنة وليست إصلاحات. في حالتي ، لدي تطبيق كامل للعمل مبني على Next بدون خادم Express مخصص - كل شيء آخر يعمل بشكل مثالي ، ولكن الآن يتعين علي إنشاء خادم Express جديد فقط بسبب مشكلة الخط المائل. يبدو أن الجهد المطلوب غير متناسب بالنظر إلى أن هذا اختراق. أود لو كان من الممكن زيادة هذا في الأولوية! لهذا السبب ، أسمع تذمرًا في فريقي حول استخدام Next بدلاً من شيء مثل Vanilla React / Angular وهو بالتأكيد يضعف حالة Next.

ملاحظة: أنا بالتأكيد أحب العمل مع Next ❤️

هذه بالتأكيد مشكلة كبيرة خاصةً لأن المسارات / تطرح صفحات خطأ وهذا يضر تحسين محركات البحث

لا يضر SEO الخاص بك. يتعامل Google مع الشرطة المائلة اللاحقة كصفحة مختلفة. الحصول على 404 لا يؤثر على مُحسّنات محرّكات البحث أكثر من أي صفحة أخرى غير موجودة في موقعك. بالإضافة إلى ذلك ، طالما أنك لم تربطها مطلقًا بشرطة مائلة ، فلن تحاول Google الزحف إليها في المقام الأول. هذه المشكلة ، على الرغم من أنها لا تزال مشكلة صالحة ، إلا أنها أقل خطورة مما تصنعه جميعًا.

MustafaHosny اللهم امين يارب

لا يجب عليك استخدام خادم Express لإجراء 301 Redirect. يعتمد على متطلباتك ، لكنني تمكنت من تلبية احتياجاتي server.js مخصص

تعد إعادة التوجيه 301 أيضًا أفضل طريقة لاستخدام مُحسّنات محرّكات البحث ، حيث لن تحصل على عقوبات محتوى مكررة للمسار المائل وغير المائل.

أنا أحب 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}`);

})();

تضمين التغريدة

لا يضر SEO الخاص بك. يتعامل Google مع الشرطة المائلة اللاحقة كصفحة مختلفة. الحصول على 404 لا يؤثر على مُحسّنات محرّكات البحث أكثر من أي صفحة أخرى غير موجودة في موقعك.

أنا أفهم وجهة نظرك أنها لا تؤذي تحسين محركات البحث بشكل خاص بالفطرة. لكنه يضع ضغطًا إضافيًا على المطورين للحصول على تعريفات عناوين URL بشكل صحيح في كل مرة ، وهو أمر يخضع لأخطاء بشرية. لا يعرف المطور الجديد في Next بالضرورة أن عنوان URL التالي (ذو المظهر الطبيعي تمامًا) سيؤدي إلى صفحة 404. <Link href='/people/'>

لا ينبغي أن يخضع إطار العمل الناضج لمثل هذه الأخطاء البشرية بشكل مثالي imo.

بالإضافة إلى ذلك ، طالما أنك لم تربطها مطلقًا بشرطة مائلة ، فلن تحاول Google الزحف إليها في المقام الأول.

مرة أخرى - توجد مشكلة ربط الأشخاص عن طريق الخطأ بـ _ www.mysite.com/people/_ بدلاً من _ www.mysite.com/people_ (يبدو أن كلاهما

يمكن أن يؤثر كلا السيناريوهين على تحسين محركات البحث.

الآن ، بغض النظر عن تأثير تحسين محركات البحث ، هناك أيضًا المعنى الدلالي لعنوان URL - إلى ماذا يشير _ www.mysite.com/people / _؟ من الناحية المثالية ، نظرًا لأنه يشير إلى دليل ، يجب أن يقوم Next بإرجاع كل ما هو في pages > people > index.js (على عكس pages > people.js لـ _www.mysite.com/people_) ولكن بدلاً من ذلك لا يُرجع أي شيء ، وهو أمر مهم جدًا. عيب كبير في كيفية عمل التوجيه.

مكتبات التوجيه الرئيسية لديها بالفعل بعض المخصصات لهذا - مثل isExact في حالة React Router

بينما أفهم من أين أتيت ، ما زلت أعتقد أن هذه مشكلة صارخة تحتاج إلى حل

هذا أيضًا أمر لا مفر منه تمامًا في حالة next export

توجد مشكلة ربط الأشخاص عن طريق الخطأ ...

توجد مشكلة ارتباط الأشخاص عن طريق الخطأ بأي عنوان url غير موجود ، فلماذا يكون /some/path/ أقل غير موجود من /some/path/dhgfiuwo ؟

هناك أيضًا المعنى الدلالي لعنوان URL

هذا أمر ذاتي للغاية ، على حد علمي ، لا يوجد أي محدد يحدد ما هو الاختلاف الدلالي. وفقًا لمواصفات URL ، يتم اعتبار عناوين URL مختلفة باستخدام الشرطة المائلة أو بدونها. يمكنني التفكير في 7 سلوكيات صحيحة مختلفة على الأقل:

  • مع وبدون محتوى مختلف تمامًا
  • مع يفعل 404 ، دون يقرر
  • 404
  • مع عمليات إعادة التوجيه إلى بدون
  • بدون عمليات إعادة التوجيه إلى مع
  • بالمحتوى نفسه وبدونه مع الإشارة المتعارف عليها إلى ب
  • مع وبدون نفس المحتوى مع الإشارة الأساسية إلى بدونه

قم بإقران هذا مع إمكانية وجود إما /pages/some-page.js و /pages/some-page/index.js (أو كليهما).

هل يجب أن يدعم next.js جميع حالات الاستخدام هذه؟ هل يجب أن تختار السلوك الافتراضي؟

أنا لست ضد هذا ، ولكن بعد محاولة تطبيق هذا من قبل ، أعتقد فقط أن هناك فارقًا بسيطًا أكثر مما يبدو في البداية.

توجد مشكلة ربط الأشخاص عن طريق الخطأ بأي عنوان url غير موجود ، فلماذا يكون / بعض / مسار / أقل غير موجود من / بعض / المسار / dhgfiuwo؟

بالنسبة للحالة /some/path/dhgfiuwo - يتوقع الناس أن يكون المسار dhgfiuwo مفقودًا. (على سبيل المثال ، لا يمكن العثور على المستخدم dhgfiuwo في النظام والطريقة users/dhgfiuwo خاطئة. غياب مستخدم في النظام أمر متوقّع.)
بالنسبة للحالة /some/path/ - يتوقع الناس أن يكون هذا المسار هو نفسه /some/path ، لأن هذا هو السلوك الافتراضي في المواقع الأخرى.
لذلك ، يكون الفشل في would/some/path/ أقل غير موجود من /some/path/dhgfiuwo .

أرى أن الآخرين قد نشروا حلولهم ، لذلك أردت مشاركة منهجي: https://github.com/DevSpeak/next-trailingslash

بعض التحسينات والدعم للصفحات الديناميكية الموجهة عندما يتعلق الأمر بـ؟ = يجب أن يتم IMO ، ولكن هذا فقط لعرض الفكرة.

للحصول على حل سريع ، يمكنك استبدال الصفحة الافتراضية _error (كما في مثالDevSpeak ).

DevSpeak ، أوصي ببعض التغييرات في الريبو الخاص بك:

إليك ما أستخدمه في مشروع 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
  }
};

ملاحظة ، يؤدي هذا أيضًا إلى تسجيل خطأ عند النقر على الصفحة ، لذا يمكنك التحقق من سجلاتك لإصلاح أي روابط / مشكلات أخرى.

DevSpeakbitjson شكرا لاقتراحاتكم. هذه بالتأكيد طريقة واحدة للتعامل مع هذا الأمر وبالتأكيد تحل المشكلة جيدًا. ولكن بالنظر إلى أن _error.jsx يُقصد به في الأصل التعامل مع الأخطاء_ وليس منطق توجيه المنزل ، في رأيي أن وجود كل هذا الكود هو أمر صعب وصريح تمامًا. لا ينبغي أن يكون توقع قيام كل مستخدم بهذا في كل قاعدة رمز متطلبًا - يجب أن يخرج هذا من الصندوق. = أنا أرى أن هذا الشرط يجب أن يتم دمجه مع منطق التوجيه ، مع خيار إلغاء الاشتراك مثل 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,
}

حتى لو لم يكن هذا حقًا خيارًا لتصدير HTML ثابتًا عبر next export ، فأنا لا أتفق مع المنطق القائل بأنه لمجرد أن Next يدعم هذه الميزة (المذهلة) ، يجب أن تعاني الأوضاع الأخرى (لا أفعل تعرف على إحصائيات الاستخدام ، لكنني أفترض أن المزيد من الأشخاص يستخدمون الوضع العادي مع الخادم بدلاً من عدم وجود خادم) خاصةً عندما يكون هذا معروفًا بأنه حالة استخدام شائعة

لمعلوماتك: هناك طلب تقديمي قد يثير اهتمامك https://github.com/zeit/next.js/issues/9081

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

Janpot Love it - سيؤدي ذلك إلى نصف الطريق ، أي أن يكون لدينا نوع من الدعم لعمليات إعادة التوجيه دون الحاجة إلى إنشاء خادم مخصص. لا يزال هذا أمرًا ضروريًا لأنه لكل مسار يضيفه المستخدم ، يجب عليهم إعداد إعادة توجيه في next.config.js - أو ربما يمكننا فقط استخدام regex للقبض على جميع الحالات مثل bitjson المذكورة:

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

في كلتا الحالتين ، إذا كان الفريق الأساسي يعطي الأولوية لهذا RFC ، فإنني أوصي بشدة أن نذهب خطوة أخرى إلى الأمام ونجعلها تكوينًا مدمجًا يمكن للمرء أن يختار الخروج منه مثل ذلك

// 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 وعملت على أكمل وجه. هذا الحل يعمل مع صريح.

GaneshKathar لا أرى كيف سيعمل هذا إذا كنت تستخدم حساب Next.js لا يستخدم التعبير

أعتقد أننا لا نستطيع الاتفاق على هذا ويجب أن يكون قابلاً للتكوين.

أريد في الواقع استخدام الشرطة المائلة اللاحقة دائمًا ، فمن الأسهل التفكير في عناوين url النسبية عندما تنتهي جميع الصفحات بشرطة مائلة لاحقة.

على سبيل المثال ، ليس من المنطقي أن يكون /about/index.tsx هو /about بدلاً من /about/ ، لكن من المفهوم الآن أن التوقعات التالية بدون خط مائل. إذا كانت جميع الصفحات ستنتهي بشرطة مائلة ، فستسمح للصفحات باحتواء صفحات فرعية في المستقبل ، وهو ما أعتقد أنه طريقة أكثر قابلية للتوسيع للصفحات.

أصبح إنشاء روابط نسبية داخل ملف /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

"استيراد رد فعل من رد فعل" ؛
استيراد التطبيق من "التالي / التطبيق" ؛

تصدير الفئة الافتراضية MyApp يوسع التطبيق {
يقدم - يجعل() {
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 شكرا على الاقتراح. لقد ساعدني ذلك. إليك كيفية تنفيذه من أجل الحفاظ على السلوك الافتراضي لأخطاء 404 غير اللاحقة (على سبيل المثال ، أنا ببساطة أعيد تصدير التنفيذ الافتراضي 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 ، ولكن بعد ذلك تحتاج إلى التأكد من عدم إعادة التوجيه في هذه الحالة.

تكمن مشكلة تنفيذ حل بديل في مكون الخطأ في أنه سيؤدي إلى حدوث خطأ إعلامي في التطوير يزعجني. بعض التحسينات في إعادة توجيه جانب العميل السابق:

ما تم تحسينه هو أنه يستخدم الآن التالي / جهاز التوجيه في جانب العميل ويتم استبدال عنوان 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 هل يمكنك تقديم أمثلة /blog/?123 ؟

شكرا للجميع لبعض الحلول الخاصة بك أعلاه. لقد عملوا!

ومع ذلك ، هل لدينا أي طريقة رسمية لإصلاح هذه المشكلة من فريق Next؟ هذه القضية كانت هنا منذ سنوات.

لا يتم عرض صفحات الدليل بشرطة مائلة في التصدير التالي

pinpointcoder هل يمكنك تقديم أمثلة /blog/?123 ؟

coodoo ليس هو ، ولكن نعم ، للأسف هذا يحدث كثيرًا. أنا حاليًا بصدد ترحيل موقع WordPress بشكل متزايد إلى Next.js ، ولسبب ما ، قرر "المطورون" الأصليون فرض شرطة مائلة على كل عنوان URL واحد ، لذلك لدينا حاليًا الكثير من الطلبات مع كلاهما شرطة مائلة ومعلمات الاستعلام.

نظرًا لأننا على وشك ترحيل أطنان من منشورات المدونة التي يشتمل عنوان URL الأساسي لها حاليًا على شرطة مائلة ، فإن هذا يمثل ألمًا كبيرًا في مؤخرتي في الوقت الحالي.

قررت استخدام خادم مخصص للتعامل مع هذا الأمر واتضح أنه من السهل القيام بذلك ، ولا يزال بإمكانك استخدام نظام التوجيه المستند إلى الملفات في next.js. بهذه الطريقة يمكنك إعادة كتابة عنوان URL الذي يراه next.js ولا يزال عنوان 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 ولا يزال هذا الخطأ يحدث. لا يصدق

هذا خطأ سيئ يحتاج حقًا إلى الإصلاح. /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.

لقد أجريت إعادة توجيه إلى عنوان 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}`)
  })
})

بالنسبة إلى مُحسّنات محرّكات البحث ، قد يساعدك 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 والأنظمة الأساسية الأخرى.

أعتقد أن هذا "الخطأ" فاجأني أكثر. بالنسبة لي ، فقد انتهك "مبدأ أقل دهشة". لقد توقعت ببساطة أن أعمل / عن / و / على وشك أن أعمل بنفس الطريقة ، منذ أن وضعت index.tsx في / pages / about / المجلد.

بدأت أولاً في إنشاء مواقع الويب في أواخر التسعينيات باستخدام HTML FTP على خادمي ، ثم انتقلت لاحقًا إلى PHP و Apache ، وفي النهاية خوادم Java. الآن أنا متخصص في تطبيقات الأجهزة المحمولة. يبدو الأمر غريبًا بالنسبة لي أن هذا السلوك ليس السلوك الافتراضي ، وأن علي كتابة صفحة خادم مخصصة لإصلاحها على خادم التطوير الخاص بي.

أخطط للقيام بتصدير ثابت ، لذلك لن يظهر في الإنتاج حتى لو لم أكتب الخادم المخصص. إنه يجعل dev وتصحيح الأخطاء أكثر إزعاجًا قليلاً.

هل يمكننا الحصول على علامة "dev / next" التي تعمل على إصلاح هذا حتى لا نحتاج نحن المطورين الكسالى إلى كتابة منطق توجيه إضافي لوقت dev / debug فقط؟

شكرا!

ملاحظة: نعم ، أعلم أن /about و /about/ عناوين URL مختلفة تمامًا. لقد أصبت بالارتباك عندما وضعت ملفًا index.tsx داخل مجلد /pages/about/ ، واكتشفت أنه يعمل فقط مع المسار /about ولكنه لا يعمل مع /about/ . سأكون أقل دهشة إذا كان العكس.

pps: لقد كان الأمر محيرًا للغاية عندما يكون لدي مكون <Link></Link> يشير إلى /about/ ويعمل كما هو متوقع. ثم عندما أضغط على تحديث في المتصفح الخاص بي ، فإنه فورًا 404s ، على الرغم من أن عنوان URL لم يتغير. كان ذلك مفاجئًا للغاية. :-د

لكن انتظر ، يزداد الأمر سوءًا! أضفنا دالة checkForTrailingSlash مخصصة داخل _error.js والتي من شأنها تجريد الشرطة المائلة اللاحقة وإعادة التوجيه. نجح هذا الأمر لفترة من الوقت حتى أضفنا (أخيرًا) صفحة 404 مخصصة ووجدنا أنه 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} />;
  }
}

يوجد خطأ فادح في نموذج التعليمات البرمجية الخاص بك: الطلبات إلى مسار الفهرس بمعامل استعلام ستؤدي إلى خطأ ، حيث ينتهي بك الأمر بمحاولة تمرير سلسلة الاستعلام فقط إلى Next.js على أنها asPath .

هذا يصلح:

  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 &

  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 واستدعائها في كلا المكانين ( getInitialProps و render ).

بواسطة

هذا سوف يصلح ولكن القرقعة خاطئة. همم
image

تضمين التغريدة

حلك يضعنا في حلقة لا نهائية:

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

مفهوم

نظرًا لأسباب خارجة عن إرادتنا ، يتعين علينا استخدام الخيار exportTrailingSlash في next.config.js .

نريد ارتباطًا بصفحة أخرى ولكننا نريد أن يكون الرابط /somepage?param=whatever .

يبدو أن الرابط التالي يحول هذا إلى /somepage/?param=whatever ونحصل على الصفحة غير موجودة.

يؤدي استخدام الحل أعلاه إلى حل مشكلة المعلمات ، ولكن عند الانتقال إلى صفحة منشورة مثل /somepage/ فإنها تدخل في حلقة لا نهائية.

أعتقد أن ronyeh قد

لإنجاز هذا العمل مع SSR ، اضطررت إلى إضافة ما يلي إلى حل pjaws &

  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 واستدعائها في كلا المكانين ( getInitialProps و render ).

لقد نجح هذا الأمر مع الصفحات التي تحتوي على getServerSideProps والآن تعود عناوين URL التي تحتوي على شرطات مائلة إلى الصفحة نفسها بدون 404.
ولكن هناك خلل واحد ، لدي عدد قليل من الصفحات التي تستخدم المسارات الديناميكية و getStaticPaths ، ولا يمكنني استخدام getServerSideProps عليها ، وبالتالي عندما يتم تصفح هذه المسارات الديناميكية بشرطة مائلة ، فإنها تُرجع أولاً 404 ثم تعيد التوجيه إلى الصفحة .

أنا أعمل مع مجلد / api / test

  • الصفحات / api / test.tsx
  • الصفحات / api / test / [id] .tsx

يعمل من أجل

  • احصل على / api / test
  • الحصول على / api / test / 123
  • GET / api / test / 123 /

واكتشفت للتو أن هذا لا يعمل

  • الحصول على / api / اختبار /

لست متأكدًا مما إذا كانت هذه مشكلة ذات صلة
P / D exportTrailingSlash = صحيح لا يحلها

هذه قضية قديمة جدًا ، فهل هناك سبب لعدم معالجتها لفترة طويلة؟

لست متأكدًا مما لا يعمل بعد الآن.

ما أفهمه هو أن المتطلبات هي كما يلي:

| | exportTrailingSlash: خطأ | exportTrailingSlash: صحيح |
| ------------------------- | ----------------------- ----- | --------------------------- |
| عنوان url ينتهي بـ / | لا ينبغي أن تعمل | يجب أن تعمل |
| عنوان url لا ينتهي بـ / | يجب أن تعمل | لا ينبغي أن تعمل |

يعمل هذا كما هو متوقع حيث:

  • محليا نستخدم exportTrailingSlash: false
  • بالنسبة لعمليات النشر (إصدارات الإنتاج) ، نستخدم exportTrailingSlash: true و nginx يحول url/ إلى url/index.html

من خلال ما يمكنني رؤيته في @ andrescabana86 هذا يعمل حيث لا ينبغي أن يكون: GET /api/test/123/ بينما GET /api/test/ لا يعمل ولا ينبغي.

Izhaki جربت كلاهما ،

  • الحصول على / api / اختبار /

وأنا أستخدم exportTrailingSlash: true

يمكنني محاولة إنشاء ريبو عام إذا أردت ، ربما نسيت شيئًا في المنتصف.

شكرا لإجاباتك

@ andrescabana86 لست متأكدًا من مقدار المساعدة التي

نحن نختبر إصدارات الإنتاج الخاصة بنا (باستخدام exportTrailingSlash: true ) محليًا باستخدام هذا البرنامج النصي في package.json :

"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 كانت المشكلة تتعلق بحقيقة أنه (كما يوحي التقرير الأولي) "

تم اختباره للتو بـ 9.4.1 و exportTrailingSlash: true .

يؤدي الانتقال إلى http://localhost:6500/admin/ إرجاع 404 عند التطوير محليًا.

لكن نفس المسار يعمل عند التصدير.

لاحظ أن هذا exportTrailingSlash يلمح إلى _exports_ فقط.

ما نقوم به هو استخدام:

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

هذا يعني أن الأشياء تعمل على النحو المنشود عندما نتطور محليًا. وتعمل بشكل صحيح عند نشرها (عبر التصدير).

أليس هذا هو الحل الصحيح القابل للتطبيق؟

إذا كان عنوان URL لا يعمل على التطوير ولكنه يعمل على الإنتاج ، ألا تعتقد أن هذا مخالف لمبدأ أقل المفاجأة؟ أعتقد أن هذا لا يزال ينبغي اعتباره خطأ.

^ ومع ذلك ، أنا متأكد من وجود سلوك متضارب سابقًا في الإنتاج بين تحديث الصفحة وحدث دفع جهاز التوجيه. لا أعرف ما إذا كان الأمر لا يزال كذلك.

@ andrescabana86Izhaki exportTrailingSlash ليست لها علاقة بذلك. يتعلق هذا الخيار بالتصدير الثابت لتطبيقات Next.js. عندما تكون القيمة true ، يتم إنشاء example/index.html ، بينما عندما تكون القيمة false ، يتم إنشاء example.html . ما أفهمه هو أن exportTrailingSlash لا علاقة له بوضع التطوير.

أعتقد أن أحد مصادر الارتباك هو أنه عندما يكون لديك exportTrailingSlash next.js يضيف شرطة مائلة لاحقة للروابط. يحدث هذا في التطوير كذلك لست متأكدًا من أنه ينبغي القيام بذلك؟ ولكن على أي حال ، هذا ليس فقط حول example/index.html مقابل example.html - تحتاج إلى تعديل الروابط أيضًا.

إذا كان عنوان URL لا يعمل على التطوير ولكنه يعمل على الإنتاج ، ألا تعتقد أن هذا مخالف لمبدأ أقل المفاجأة؟ أعتقد أن هذا لا يزال ينبغي اعتباره خطأ.

قد أكون مخطئًا ، لكن خيار exportTrailingSlash كان لخوادم nginx التي لم يتم تكوينها لخدمة /something.html عندما يكون عنوان url هو /something .

هذا ليس هو الحال مع الخادم التالي المستخدم للتطوير المحلي. إذن ما يصلح وما لا يصلح يعتمد على ما يخدم تطبيقك.

يمكنك إثبات أنه عندما يكون 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 s. على سبيل المثال ، تعمل عناوين URL /about و /about/ ما يرام.

في الشكل الحالي ، يحاكي بشكل أساسي التوجيه الأصلي لـ Next.js. الجانب السلبي: يتطلب تخصيص server.js ، وسيتعين عليك دعمه يدويًا لعناوين URL "الأعمق" (مع "مجلدات فرعية" إضافية) ، على سبيل المثال /company/about/ . ولكن يبدو أنه حل بسيط نسبيًا لأولئك الذين يستخدمون بالفعل server.js المخصص في مشروعهم.

لإنجاز هذا العمل مع SSR ، اضطررت إلى إضافة ما يلي إلى حل pjaws &

  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 واستدعائها في كلا المكانين ( getInitialProps و render ).

لقد نجح هذا الأمر مع الصفحات التي تحتوي على getServerSideProps والآن تعود عناوين URL التي تحتوي على شرطات مائلة إلى الصفحة نفسها بدون 404.
ولكن هناك خلل واحد ، لدي عدد قليل من الصفحات التي تستخدم المسارات الديناميكية و getStaticPaths ، ولا يمكنني استخدام getServerSideProps عليها ، وبالتالي عندما يتم تصفح هذه المسارات الديناميكية بشرطة مائلة ، فإنها تُرجع أولاً 404 ثم تعيد التوجيه إلى الصفحة .

gauravkrp هذه في الواقع إضافة مهمة للغاية ، نظرًا لأن حل AlexSapoznikov سيستمر في الواقع في إرجاع 404 للصفحة إلى Google (نظرًا لأن إعادة التوجيه تحدث على العميل). أتخيل أن تحسين محركات البحث هو سبب رئيسي يستخدمه الكثير منا Next.js في المقام الأول.

أعتقد أيضًا أن وضع هذا في getInitialProps يجب أن يعمل فقط في كل مكان ، والقطعة داخل الوظيفة الرئيسية غير ضرورية في هذه المرحلة. التحذير الرئيسي هنا هو أنك تفقد التحسين التلقائي الثابت من خلال امتلاك هذا - ربما يكون أفضل من مجموعة من 404s ، على الرغم من ذلك.

لبعض المشاركة ...

مشروعي هو 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 build و 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/
});

ختاما

ليس لدي مشكلة عند إعادة التوجيه من خلال النقر على تطبيق العميل ،
التحديث الجاد أيضًا يعمل على static route .

ولكن سيتم 404 عند التحديث الصعب على dynamic route ،
مثل /album/[id].jsx أو /album/123 ،
لذا فإنني أتطلع إلى حل هذه المشكلة باستخدام الآلية التالية.

على سبيل المثال
عند الضغط على 404 بسعر /album/123 ،
يجب أن يستمر الخادم في توفير محتوى html ،
سيستمر المتصفح في تحميل الصفحة دون مشكلة ،
عند تشغيل Next.js ، يجب أن يتعامل معه next/router تلقائيًا.

هل هناك حل مؤقت لهذه القضية على الإنتاج؟

نحن على وشك الحصول على ميزة لإصلاح هذا — يوم أو نحو ذلك!

هل هناك حل مؤقت لهذه القضية على الإنتاج؟

يوجد الكثير في هذا الموضوع ، لكنني حاليًا أستخدم ما نشرته gauravkrp مؤخرًا ، وهو يعمل جيدًا بالنسبة لي.

يمكنك متابعة العلاقات العامة هنا: # 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/ "

Valnexus راجع # 13333 ، يتضمن خيارًا تجريبيًا:

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

كم من الوقت تستغرق الميزة للانتقال من كناري إلى إتقان؟

عندما يكون جاهزا. لا تزال هناك حالات متطرفة في المعالجة يتم حلها. بمجرد أن يتم إصلاحها يمكن أن تتحول إلى مستقر.

تضمين التغريدة

لقد جربت أحدث إصدار من الكناري التالي (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"> لإخبار روبوتات البحث بالصفحة التي يجب الزحف إليها ويجب وضع علامة على الإصدارات الأخرى على أنها مكررة.

لذا فإن إعادة التوجيه هي طريقة قابلة للتطبيق لتحسين محركات البحث على موقع الويب الخاص بك. يمكنك قراءة المزيد من المعلومات هنا .

ziserman إذا كانت لدينا عدة طرق لحلها ، فيجب أن نحتفظ بنفس عنوان url بدون إعادة توجيه لتجربة المستخدم.

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

لدى Nuxtjs عدة خيارات للاختيار (غير محدد ، صحيح ، خطأ)

هل يجب أن يكون لدى Nextjs خيارات سيرفيرال للاختيار منها أيضًا؟

سبب إعادة التوجيه هو التأكد من أن محركات البحث لا ترى محتوى مكررًا. ما هي حالة الاستخدام الخاصة بك بالضبط؟

Janpot تحتوي واجهة برمجة التطبيقات الخاصة بنا على شرطات مائلة في العديد من الأماكن. أحدث إصدار يثير الكثير من 404 على الواجهة الخلفية نظرًا لأن عناوين URL ذات الخطوط المائلة اللاحقة (/ api / test / -> / api / test) لا تتطابق

لا أعرف ما إذا كان سيعمل مع الجميع ، لكنني وجدت هذا الحل المناسب لي. ضعه في ملف _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 /> s على جانب العميل بشكل صحيح ، لكن إعادة التوجيه من جانب الخادم ستتطلب تكوينًا يدويًا. المشاريع التي تم نشرها مع الهدف بدون خادم أو next start ستقوم بتهيئة هذه الإعدادات تلقائيًا.

Timer بمجرد وصول هذا الإصدار الكامل ، هل سنظل بحاجة إلى استخدام الخيار التجريبي؟

Timer بمجرد وصول هذا الإصدار الكامل ، هل سنظل بحاجة إلى استخدام الخيار التجريبي؟

لا ، سيكون متاحًا كما هو.

أعتقد أن الخيار trailingSlash لن يعمل مع next export ؟ ما هي أفضل طريقة لإعادة توجيه /page/ إلى /page (أو العكس) في صفحات جيثب مثلاً؟

أعتقد أن الخيار trailingSlash لن يعمل مع next export ؟ ما هي أفضل طريقة لإعادة توجيه /page/ إلى /page (أو العكس) في صفحات جيثب مثلاً؟

على حد علمي ، لا تحتوي صفحات github على ميزة إعادة التوجيه. هذا يعمل خارج الصندوق على vercel.com على الرغم من أنه مجاني أيضًا لمشاريع الهوايات (مثل صفحات github).

المشاريع التي تستخدم next export سيتم تحديث جميع <Link /> s على جانب العميل بشكل صحيح ، لكن إعادة التوجيه من جانب الخادم ستتطلب تكوينًا يدويًا. المشاريع التي تم نشرها مع الهدف بدون خادم أو next start ستقوم بتهيئة هذه الإعدادات تلقائيًا.

مرحبا Timer هل يمكن أن تشرح أكثر؟ كيف يمكنني التكوين يدويًا؟ إذا هذا هو وضعي. على موقع الويب الخاص بي ، استخدم next-i18next . بعد أن قمت بالنشر باستخدام next build && next export ، تعمل جميع الروابط الداخلية ولكن عند إدخال عنوان URL يدويًا ، لا يعمل أي منها ويؤدي إلى خطأ 404. من هنا قررت استخدام trailingSlash:true ولذا فإن إدخال /pricing يدويًا سيعمل الآن ولكن /zh/pricing يؤدي إلى أخطاء 404.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات