Next.js: [RFC] Server (weniger) Middleware

Erstellt am 1. Mai 2019  ·  52Kommentare  ·  Quelle: vercel/next.js

Featureanfrage

Derzeit gibt es viele Benutzer, die einen benutzerdefinierten Server erstellen, um middleware Verhalten auszuführen, zum Beispiel serverseitiges Parsen von Anforderungskörpern, Cookies usw. Derzeit bietet Next.js keine Möglichkeit, dies ohne einen benutzerdefinierten Server zu handhaben. Das heißt, es kann nicht in serverlosen / anderen Umgebungen durchgeführt werden.

Beschreiben Sie die gewünschte Lösung

Im Idealfall würden Benutzer Middleware als Top-Level-Export definieren. Das bedeutet, dass Seiten Middleware-Anforderungen definieren können:

// PageContext being the same values as `getInitialProps`'s context
export async function middleware({req, res}: PageContext) {
  // do something with `req` / `res`
}

function IndexPage() {
  return <h1>Hello world</h1>
}

export default IndexPage

Dies führt jedoch auch zu der Komplexität des Code-Splits / Tree-Shakes von Benutzerimporten, die nur Server sind.

Also würde ich für die anfängliche Implementierung (und schrittweise auf die obige Implementierung hinarbeiten) mit der Unterstützung von Middleware in pages_document.js die immer serverseitig gerendert wird, so dass es sinnvoll ist, sie dort zu haben.

Eine Sache, die angesprochen wurde, ist "warum kann dies nicht einfach in getInitialProps von _document erfolgen".

Der Grund, warum wir eine neue Methode benötigen, ist, dass der Lebenszyklus des Aufrufs von getInitialProps so aussieht:

  • Seiten/_app.js getInitialProps wird aufgerufen,
  • Seiten/_app.js getInitialProps ruft die getInitialProps der Seite auf
  • Seiten/_document.js getInitialProps heißt
  • page/_document.js getInitialProps ruft renderPage
  • renderPage ruft Reacts renderToString und gibt die HTML-, Head-Tags und Styles zurück.
  • renderToStaticMarkup wird aufgerufen, um die _document-Shell zu rendern
  • Anfrage wird mit send-html.ts beendet, das Etag usw. hinzufügt.

Wenn Middleware verwendet wird, muss sie im Allgemeinen vor getInitialProps aufgerufen werden, da Sie möglicherweise etwas analysieren, das in getInitialProps

Die Middleware muss also früher aufgerufen werden.

Das heißt, der Lebenszyklus würde wie folgt aussehen:

  • Seiten/_document.js Middleware heißt
  • Seiten/_app.js getInitialProps wird aufgerufen,
  • Seiten/_app.js getInitialProps ruft die getInitialProps der Seite auf
  • Seiten/_document.js getInitialProps heißt
  • page/_document.js getInitialProps ruft renderPage
  • renderPage ruft Reacts renderToString und gibt die HTML-, Head-Tags und Styles zurück.
  • renderToStaticMarkup wird aufgerufen, um die _Dokumenten-Shell zu rendern
  • Anfrage wird mit send-html.ts beendet, das Etag usw. hinzufügt.

Für die erste Implementierung möchten wir also etwas wie:

// pages/_document.js

// PageContext being the same values as `getInitialProps`'s context
export async function middleware({req, res}: PageContext) {
  // do something with `req` / `res`
}

// rest of _document.js

Hilfreichster Kommentar

Hey @timneutkens und @Timer -

Ich habe #7297 und die neue Dokumentation durchgesehen und es scheint, dass die Middleware-Unterstützung noch nicht da ist, oder? Würde gerne next-i18next neu schreiben und die benutzerdefinierten Serveranforderungen entfernen (https://github.com/isaachinman/next-i18next/issues/274).

Alle 52 Kommentare

Diese neue Funktion soll standardmäßig Projekte wie next-i18next unterstützen, die derzeit einen benutzerdefinierten Server erfordern, cc @isaachinman

Relevanter Code: https://github.com/isaachinman/next-i18next/blob/master/src/middlewares/next-i18next-middleware.js#L52

Was ist mit React-Bugs, die NUR durch Ändern des resultierenden HTML-Codes als String behoben werden können?
Ich habe vorhin eine gepostet: https://github.com/zeit/next.js/issues/6718
Mir ist klar, dass dies zusätzliche Bedenken hinsichtlich des Streamings usw. aufwirft. Und es kann ein Kaninchenbau sein. Lassen Sie uns trotzdem darüber diskutieren, um uns (Verbraucher) auf die offizielle Position im Moment aufmerksam zu machen. Sollten wir eine pre und post Stufe oder zwei verschiedene Middlewares haben. Oder lohnt es sich wegen der zusätzlichen Komplexität einfach nicht?

@timneutkens Wie über Slack besprochen - möchte nur klarstellen, dass wir hier über Vanille req und res und Express-spezifische Felder wie req.body und req.query sprechen http Implementierung.

Ist das korrekt?

@isaachinman ja!

@ivan-kleshnin Ich verstehe nicht, wie das zusammenhängt, Sie könnten res.end auf ähnliche Weise überschreiben, wie Sie es bereits in diesem Problem tun, auch wenn ich es nicht empfehlen würde.

Nur ein kurzer Gedanke und möglicherweise ein Bikeshedding, aber wäre es sinnvoll, die Primitiven Request und Response aus der Fetch-API zu verwenden? Es scheint, als könnte es schön sein, dieselben Primitiven für Server-, Serviceworker- und Frontend-Code verwenden zu können.

Ich bleibe lieber bei Node.js req / res weil:

  • Es ist das, was an getInitialProps
  • Es ist mit den meisten Middlewares kompatibel

@timneutkens Stimme dem voll und ganz zu. Ich wollte erwähnen, dass nach der Landung dieser Funktion wahrscheinlich Platz sein würde, um kleine Pakete herauszugeben, um einen 1:1-Ersatz für Dinge wie Express zu ermöglichen. Es ist viel besser, mit den Node-Standardeinstellungen zu beginnen.

♥️ es!

Ich habe diesen Workaround verwendet, der es mir ermöglicht, Middleware zu getInitialProps() hinzuzufügen:

Sehen Sie sich hier eine Demo zum Hinzufügen von body-parser an: https://codesandbox.io/s/n3yj15mk7p

✅ Funktioniert für lokale Entwickler/benutzerdefinierte Server ( server.js )
✅ Funktioniert auf target: 'serverless'
✅ Kann alles analysieren (Formulare, JSON usw.)
✅ Wird pro Seite angewendet
✅ Aktiviert No-JS-Formulare

Hey @timneutkens und @Timer -

Ich habe #7297 und die neue Dokumentation durchgesehen und es scheint, dass die Middleware-Unterstützung noch nicht da ist, oder? Würde gerne next-i18next neu schreiben und die benutzerdefinierten Serveranforderungen entfernen (https://github.com/isaachinman/next-i18next/issues/274).

Das würde auch unser Unternehmen gerne sehen. Wir haben ein internes Authentifizierungssystem, das derzeit einen benutzerdefinierten Server erfordert, und die Möglichkeit, diese Logik auf Middleware zu übertragen und den benutzerdefinierten Server zu entfernen, würde unser Projekt-Upgrade erheblich vereinfachen (wir haben Hunderte von Projekten, die Next verwenden - jedes größere Upgrade hatte eine anständige Menge an Schmerz und Pushback, außer den nächsten 9 - danke für die Rückwärtskompatibilität!).

Nur meine zwei Cent hier: Wäre es nicht sinnvoll, ein _middleware.js im Verzeichnis pages/api/ hinzufügen zu können?

@zomars Dies ist hauptsächlich für tatsächliche Frontend-Routen relevant. Es ist bereits möglich, Middleware in Ihren v9-API-Routen zu verwenden.

@isaachinman Gibt es ein vollständig funktionierendes Beispiel, auf das Sie sich beziehen können?

@ amardeep9911 Ich könnte mich irren, aber eine Möglichkeit besteht darin, die umschließen .
https://github.com/zeit/next.js/tree/canary/examples/api-routes-middleware

Hallo @timneutkens , ich Anfrageobjekt zugreifen, wenn ich den Middleware-Kontext

> GET /                        
{                              
  err: undefined,              
  req: undefined,              
  res: undefined,              
  pathname: '/',               
  query: { amp: undefined },   
  asPath: '/',                 
  AppTree: [Function: AppTree] 
}                              

Soll ich ein separates Problem erstellen? Oder ist das eine normale Einschränkung?

@HelloEdit Ich scheine mich daran zu erinnern, dass req/res nicht definiert sind, es sei denn, Ihre Seite verfügt über die Funktion .getInitialProps(), da Ihre Seite ohne getInitialProps möglicherweise statisch ist

ho, danke für deine antwort. aber ich hoffe aufrichtig, dass es nicht das erwartete Verhalten ist: Die Middleware würde ihr ganzes Interesse verlieren, wenn getInitialProps benötigt würde, um sie zum Laufen zu bringen, oder ich habe einen Punkt übersehen 🤔
Meine Interpretation ist, dass die Middleware immer serverseitig ausgeführt wird, wenn die Anfrage gestellt wird.

@timneutkens nett, freue mich darauf, wenn das umgesetzt wird :) Frage an dich. würde dies Auswirkungen auf die automatischen statischen Optimierungen hier skizzierten ?

Es würde nicht mit statischen Seiten funktionieren.

Hey @timneutkens , wird die Middleware auch auf API-Routen oder nur auf Nicht-API-Seiten angewendet? Vielen Dank!

Hallo Leute,
Ich möchte mich der Notwendigkeit anschließen, dies mit etwas zu kombinieren, auf das in https://github.com/zeit/next.js/issues/9013 verwiesen wurde

Ich persönlich bin der Meinung, dass nextjs expressjs und seine Middleware übernehmen und nicht am Ende viele Dinge neu aufbauen sollte.
Wir verwenden beispielsweise auch expressjs-Middleware, um nahtlose msgpack-basierte Antworten zu geben (https://github.com/textbook/express-msgpack). Eine Menge Leute tun dies auch für Protokollpuffer usw.

Es gibt jede Menge solcher Beispiele und ich befürchte, dass nextjs einen langen Zyklus durchlaufen wird, um sie alle neu zu erstellen (oder von Endbenutzern erwarten, dass sie sie neu implementieren).

@sandys Meiner Meinung nach wird Next.js aufgebläht, wenn zu viele Dinge hinzugefügt werden, was möglicherweise die Leistung und Optimierung beeinträchtigt. Außerdem ist die Konfiguration nicht bei allen gleich, so dass mehrere Standardeinstellungen Dinge von denen beschädigen können, die sie nicht verwenden. Noch sicherer ist die persönliche Umsetzung.

Bei allem Respekt, das ist die Vermutung, dass die Nutzung von expressjs funktioniert
weniger leistungsfähig zu sein, als es selbst zu tun.

Und ja - ich stimme zu, dass die Konfiguration von jedem so sein wird
anders..in der Tat so unterschiedlich, dass es sinnvoll sein kann, eine riesige Menge zu nutzen
bereits vorhandenes Middleware-Plugin-Ökosystem.

Ich bin nicht gegen eine benutzerdefinierte Middleware von nextjs. Allerdings versuche ich zu setzen
eine andere Sichtweise vorschlagen.

Am Montag, 21. Oktober 2019, 23:25 Uhr schrieb Hoang, [email protected] :

@sandys https://github.com/sandys Meiner Meinung nach zu viele Dinge hinzufügen
wird Next.js aufgebläht, was möglicherweise seine Leistung beeinträchtigt und
Optimierung. Außerdem ist nicht jede Konfiguration gleich, also haben
Mehrere Standardeinstellungen können Dinge von denen zerstören, die sie nicht verwenden. Es ist immer noch
sicherer persönlich umzusetzen.


Sie erhalten dies, weil Sie erwähnt wurden.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/zeit/next.js/issues/7208?email_source=notifications&email_token=AAASYU4MXYPLGM2IBNHQHDTQPXUJXA5CNFSM4HJUGS7KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63ZDNW2H44
oder abmelden
https://github.com/notifications/unsubscribe-auth/AAASYU55YYIC6FZYIY7KOLDQPXUJXANCNFSM4HJUGS7A
.

@sandys Ich glaube, du

Zeit.co setzt auf Serverless und eine der Kernfunktionen von Next.js ist die Serverless-Unterstützung. Express vereitelt diese Philosophie/Architektur vollständig, da Sie einen zentralisierten Einstiegspunkt/Routing benötigen.

Sie können also sicher sein, dass Express.js nicht als Basis verwendet wird (und deshalb verwendet Next micro ).

Die Verwendung von express ist für Next.js nicht erforderlich. Aber auch micro wird nicht für Next.js verwendet.

Je nach verwendetem Ausgabeziel wird der Node.js Plain HTTP Server verwendet, der die beste Performance (kein weiterer Overhead) gewährleistet. Im Ziel serverless wir nur die API req / res als Low-Level-API bereit.

Außerdem würde die Bündelung von express bedeuten, dass die Bündelgröße für serverlose Funktionen deutlich größer wäre.

An einem Punkt dachte ich, dass diese Middleware auch auf dem Client ausgeführt werden könnte, aber nachdem ich dies noch einmal gelesen habe, denke ich, dass der Plan darin besteht, diese nur auf dem Server auszuführen. Ist das eine richtige Annahme?

@timneutkens danke für die Antwort - deine Antwort ist das, was ich immer angenommen habe. Am Ende des Tages ist genau das der Kompromiss, den Sie entscheiden müssen.

expressjs ist 300-400kb (https://bundlephobia.com/[email protected]) . Für diejenigen von uns, die nicht serverlos arbeiten, erschließt es ein riesiges Ökosystem gebrauchsfertiger Middleware.

Ein Mittelweg (!!) besteht darin, die expressjs-API zu pflegen, aber selbst zu implementieren. Auf diese Weise kann Nextjs eine minimale Größe für Serverless bereitstellen und gleichzeitig in ein großes Ökosystem für andere eingebunden werden.

@goldenshun richtig. Beachten Sie, dass ich zu diesem Zeitpunkt (in wenigen Monaten veröffentlichen wir Next.js 9) nicht mehr fest davon überzeugt bin, dass dieser RFC der richtige Weg ist. Aber ich denke noch darüber nach. Besonders bei Plugins könnten wir ein next-plugin-helmet (für Sicherheitsheader) haben und die anderen Fälle für Middleware könnten auch abgedeckt werden.

@sandys Ich verstehe nicht ganz, was du mit diesem Thread erreichen willst. Dieser RFC deckt einen Grenzfall ab, in dem Benutzer ihren benutzerdefinierten Server loswerden möchten.

Sie können Express bereits ausführen, wenn Sie dies gemäß der benutzerdefinierten Server-API möchten: https://github.com/zeit/next.js#custom -server-and-routing

Insgesamt ist es mit Next.js 9 viel unwahrscheinlicher, dass Sie sowieso einen benutzerdefinierten Server benötigen.

Ich denke, es gibt immer noch ein gutes Argument für die Middleware-Unterstützung, das das aktuelle Plugin-RFC nicht abdeckt.

Zum Beispiel würde etwas wie next-plugin-helmet einen zusätzlichen Plugin-Hook benötigen, der auf die Request und Response Objekte zugreifen und diese ändern kann, um Header zu verwenden und zu setzen.

// on-request.js
const handler = helmet(config);

export default async function onRequest({ req, res }: { req: Request, res: Response }): void {
  // called upon receiving a request, allows you to modify response headers, e.g.:
  handler(req, res);
}

Dieser vorgeschlagene Hook klingt im Allgemeinen nach einem guten Diskussionspunkt, jedoch ist die Verwendung von Umgebungsvariablen als Konfiguration nicht ideal, da die Helmkonfiguration kompliziert sein kann (verschachtelte Objekte) und dynamische Werte basierend auf dem Request Objekt verwendet:

const config = {
  contentSecurityPolicy: {
    scriptSrc: ["example.com", (req) => req.locals.nonce]
  }
}

Dies konnte nicht mit dem nextjs Schlüssel in den package.json des Plugins konfiguriert werden, sodass eine zusätzliche Möglichkeit zum Laden der Konfiguration erforderlich wäre, damit es ein Plugin ist.

Lust auf Gedanken

@timneutkens Ich glaube, Sie haben

Wie ich in meinem Kommentar zum Custom Routes RFC erwähnt habe , bin ich immer noch auf der Suche nach einer besseren Lösung für die dynamische Umleitungslogik als getInitialProps und hoffte, dass Middleware auf Seitenebene, die sowohl auf Client als auch auf Server ausgeführt wird, eine Lösung sein könnte. Der Teil, der die Leute mit Weiterleitungen innerhalb von getInitialProps verwirrt, ist, dass es keine Möglichkeit gibt, das Rendern der Seite zu stoppen. Wir benötigen immer benutzerdefinierten Code, der wie folgt aussieht:

const Page = ({ isUserAuthenticated }) => {
  if (!isUserAuthenticated) return null; // bail since Page is going to render even when we call redirectToLogin.

  return (<div>...</div>);
}
Page.getInitialProps = async (ctx) => {
    if (!userIsAuthenticated(ctx) {
      logger.info('accessToken not found, redirecting user to login');
      redirectToLogin({ redirectTo: ctx.asPath, ctx });
      return {};
    }

    return { isUserAuthenticated: true };
  };

Ich glaube, ich habe nach etwas Ähnlichem wie dem ursprünglichen Vorschlag in diesem Thread gesucht:

export function middleware(ctx, next) {
  const { req, res } = ctx; // Same ctx that will eventually be passed to getInitialProps
  if(shouldRedirect(...)) {
    if (res) {
      res.redirect('/login');
    } else {
      Router.push('/login'); // also works on the client
    }
  }
  next(); // Similar to express, call the next middleware in the chain but only if we aren't redirecting
}

function IndexPage() {
  return <h1>Hello world</h1>
}

export default IndexPage

Dies ist tatsächlich der Fall _only_ Verwendung ich daran denken , können die Vorteile dieser Art von Middleware würde, so wir in der Lage sein könnten , indem sie diese eine explizite den Umfang des Problems zu verengen redirect Funktion:

export function redirect(ctx) {
  if(shouldRedirect(ctx)) {
    return '/login';
  }
  return false; // null, undefined, etc. means no redirect
}

Ich persönlich denke, dass dies sehr sinnvoll ist, da es uns ermöglicht, eine ganze Reihe externer Middleware für Express-/Koa-/jegliche andere Serverumgebungen bereitzustellen. Eine Art kostbare Einheitlichkeit mit dem nächsten Ökosystem ist am Ende des Tunnels zu sehen :)

Ich denke stark, dass dies den Fall von harten/schweren Implementierungen von Plugins und Middleware aus allen möglichen Ökosystemen nutzen kann.

Wir verwenden i18n und sind gezwungen, einen benutzerdefinierten Server zu erstellen oder die Übersetzungen über einige Lamdas von Seiten/Api bereitzustellen. Für mich scheint es überkonstruiert zu sein.

Cookies-Parsing, Body-Parsing und einige andere Middlewares, die bereits für API-Routen vorhanden sind, könnten hier möglicherweise verwendet werden (natürlich Opt-in).

Einige andere praktische Fälle sind: Überprüfen Sie Authentifizierungstoken für jede Anfrage, testen Sie Umleitungen usw.

Ich hoffe wirklich, dass dieser RFC herauskommt und uns allen hilft.

Und danke an das ganze zeit-Team für diese tolle Arbeit, ihr macht das großartig, Leute.

Soweit ich die Plugins verstehe, ist rfc eine Art v2 davon. viele Leute haben Probleme mit dem serverlosen i18n, @timneutkens Gibt es etwas, was Sie dazu sagen / teilen können, vielleicht insbesondere in Bezug auf die Unterstützung von next-i18next? https://github.com/isaachinman/next-i18next/issues/274

Ich würde gerne eine _middleware.js Datei sehen, die es uns ermöglicht, allen req und res Parametern zusätzliche Middleware hinzuzufügen (ähnlich wie Express-Middlewares, die nicht seitenspezifisch sind). Zum Beispiel habe ich ein Workaround verwendet, um eine wiederverwendbare Middleware-Funktion zu erstellen, die es mir ermöglicht, compression , morgan , passport und cookie-sessions für alle API-Anfragen:

import bodyParser from "body-parser";
import compression from "compression";
import morgan from "morgan";
import moment from "moment-timezone";
import passport from "passport";
import session from "cookie-session";
import applyMiddleware from "~middlewares/applyMiddleware";
import { sendError } from "~shared/helpers";

const { inProduction, cookieSecret } = process.env;

export default next => async (req, res) => {
    try {
        morgan.token("date", () => moment().format("MMMM Do YYYY, h:mm:ss a"));

        await applyMiddleware([
            compression({
                level: 6,
                filter: (req, res) =>
                    req.headers["x-no-compression"]
                        ? false
                        : compression.filter(req, res),
            }),
            session({
                path: "/",
                name: "app",
                maxAge: 2592000000, // 30 * 24 * 60 * 60 * 1000 expire after 30 days
                keys: [cookieSecret],
                httpOnly: true,
                // sameSite: inProduction, // specifies same-site cookie attribute enforcement
                // secure: inProduction,
            }),
            morgan(
                inProduction
                    ? ":remote-addr [:date] :referrer :method :url HTTP/:http-version :status :res[content-length]"
                    : "tiny",
            ),
            passport.initialize(),
            bodyParser.urlencoded({ extended: true }),
        ])(req, res);

        return next(req, res);
    } catch (error) {
        return sendError(error, res);
    }
};

Verwenden Sie außerdem eine zusätzliche Middleware-Funktion, um die Sitzungsauthentifizierung zu überprüfen:

import get from "lodash/get";
import { User } from "~models/instances";
import { sendError } from "~shared/helpers";
import { badCredentials } from "~shared/errors";

/**
 * Middleware function to check if a user is logged into a session and the session is valid.
 *
 * <strong i="16">@async</strong>
 * <strong i="17">@function</strong>
 * <strong i="18">@param</strong> {object} - req
 * <strong i="19">@param</strong> {object} - res
 * <strong i="20">@returns</strong> {function}
 */
export default next => async (req, res) => {
    const _id = get(req, ["session", "id"]);
    if (!_id) return sendError(badCredentials, res);

    const existingUser = await User.findOne({ _id });
    if (!existingUser) return sendError(badCredentials, res);

    next(req, res);
};

Und dann schließe ich meine API-Route(n) manuell damit ein:

import withMiddleware from "~middlewares";
import { User } from "~models/instances";
import { sendError } from "~shared/helpers";
import requireAuth from "~strategies/requireAuth";

/**
 * Retrieves logged in user app settings.
 *
 * <strong i="24">@async</strong>
 * <strong i="25">@function</strong> getProfile
 * <strong i="26">@param</strong> {object} - req
 * <strong i="27">@param</strong> {object} - res
 * <strong i="28">@returns</strong> {res}
 */
const getProfile = async (req, res) => {
    try {
        const { id: _id } = req.session;

        const signedinUser = await User.findOne({ _id }, { password: 0, __v: 0 });
        if (!signedinUser) throw String("Unable to locate signed in user profile.");

        res.status(200).json({ signedinUser });
    } catch (err) {
        return sendError(err, res);
    }
};

export default withMiddleware(requireAuth(getProfile));

Während es funktioniert, ist der Nachteil, dass jede API-Seitenfunktion manuell mit dieser withMiddleware Funktion requireAuth ) und sie manuell req und res an die next Funktion... und so weiter. Durch das Freilegen einer _middleware.js Konfiguration könnte man Middlewares an einen Stack anhängen und sie auf alle zukünftigen Anfragen/Antworten anwenden (idealerweise einmal, anstatt für jede Anfrage) und als Ergebnis sollte dies einige der Redundanz bei der API-Einrichtung.

@timneutkens Wollte überprüfen, warum dieser RFC noch geöffnet ist. Die Änderungen unter https://github.com/zeit/next.js/pull/7209 wurden in canary zusammengeführt. Wann wird diese in master zusammengeführt und kann unter Next.js 9 verwendet werden.

Es ist unwahrscheinlich, dass dies in absehbarer Zeit landen wird, da es aufgrund der kommenden Funktionen einiges an zusätzlicher Komplexität ohne zusätzlichen Gewinn mit sich bringt.

Es ist unwahrscheinlich, dass dies in absehbarer Zeit landen wird, da es aufgrund der kommenden Funktionen einiges an zusätzlicher Komplexität ohne zusätzlichen Gewinn mit sich bringt.

Ich hoffe, das Team schlägt eine Alternative für die Verwendung von Middleware auf der Clientseite vor oder wenn wir Middleware auf der Clientseite überhaupt nicht verwenden können!

Vielen Dank!

Dieser Vorschlag deckte keine clientseitige Middleware ab.

@timneutkens Die aktuelle _document Seite, da sich die Middleware hauptsächlich darauf konzentriert, die Eigenschaften IncomingMessage und ServerResponse ändern ... können wir sie einfach ändern? stattdessen direkt innerhalb der Server Klasse?

Zum Beispiel habe ich einen funktionierenden Prototyp, der die nextConfig Eigenschaft des Servers verwendet, um eine Middleware einzuschließen, die in einer applyMiddleware Eigenschaft innerhalb der next.config.js Datei angegeben ist. Diese Eigenschaft definiert ein Array von Middleware-Funktionen und eine optionale routes Konfigurationsoption – sie wendet die Middleware bedingt auf bestimmte Routen an – und ist wie folgt strukturiert:

next.config.js

const bodyParser = require("body-parser");
const morgan = require("morgan");
const passport = require("passport");
const session = require("cookie-session");

const { cookieSecret } = process.env;

module.exports = {
  applyMiddleware: [
    [
      session({
        path: "/",
        name: "app",
        maxAge: 2592000000, // 30 * 24 * 60 * 60 * 1000 expire after 30 days
        keys: [cookieSecret],
        httpOnly: true,
      }), 
      { routes: ['/api'] }
    ]
    [ morgan('tiny'),  { routes: [ '/api', '/_error' ]  } ],
    passport.initialize(),
    bodyParser.urlencoded({ extended: true }),
  ],
}

Oder, wenn Sie Ihre eigene(n) Middleware-Funktion(en) einbinden möchten, wird dies auch unterstützt ( alle Routen-Middleware oder bedingte Routen-Middleware ):

module.exports = {
  applyMiddleware: [
    (req, res) => {
      res.setHeader('all-routes-middleware', 'hello world!!!!')
    },
    [
      (req, res) => {
        res.setHeader('conditional-routes-middleware', 'bye world!!!!')
      },
      { routes: ['/api/user'] },
    ],
  ],
}

Dann werden diese Middlewares in der Klasse Server auf die Parameter IncomingMessage und ServerResponse innerhalb der Methode run angewendet.

Der Vorteil dieses Ansatzes besteht darin, dass all dies vom Entwickler abstrahiert wird, es sich um ein Opt-In handelt, keine _document Seite erfordert und sowohl in Server- als auch in serverlosen Umgebungen funktioniert.

Lass mich wissen was du denkst.

@mattcarlotta , das nicht funktioniert, da Server nicht in allen Fällen verwendet wird, wenn Next.js verwendet wird, zB in Serverless. Ebenso wird next.config.js nur zum Zeitpunkt dev und build geladen und wir werden keine Optionen hinzufügen, die vom Booten zu next.config.js abhängen. Wir raten zunehmend davon ab, die Konfigurationsoptionen hinzuzufügen, die Laufzeit erfordern, wie publicRuntimeConfig usw., damit wir next.config.js auf next start schließlich nicht benötigen können, da die Leute dazu neigen, Tonnen von Modulen zu laden, die in der Produktion nicht benötigt werden ( um die Bootzeit für next start zu verbessern). Auf Serverless laden wir bereits next.config.js nur auf dev/build.

Außerdem gibt es kein klares korrektes Verhalten bei der Einführung dieser Methoden, zum Beispiel sind Next.js-Apps zunehmend Hybriden aus SSG / SSR und Middlewares können nicht für statische Dateien ausgeführt werden, da sie von einem Edge-Cache bereitgestellt würden.

https://github.com/zeit/next.js/issues/7208#issuecomment -488317652

Dieser Fall wird übrigens durch die Rewrites/Redirects und die neuen Datenabrufmethoden abgedeckt.

Hey @timneutkens , ich weiß, dass diese Funktion noch experimentell ist, aber denken Sie, dass es ein potenzielles Problem gibt, wenn Sie dies nur zum Setzen einiger Cookies verwenden. Wir haben nur SSR-Seiten.

Wenn Sie Cookies setzen möchten, ist es besser, API-Routen zu verwenden und umzuleiten.

Könnte diese Middleware zusätzlich zu app.render() oder nextRequestHandler() @timneutkens verwendet werden ? Wie in den Beispielen des benutzerdefinierten Servers https://github.com/zeit/next.js/blob/canary/examples/custom-server-typescript/server/index.ts

Ich frage das, weil unser Stack ein Headless-CMS (Cockpit) und Next.js enthält, das Routing zwischen den beiden derzeit (wirklich) schwierig ist (die Routen befinden sich auf dem CMS und Slugs / URLs / Seiten könnten hinzugefügt / entfernt werden) / jederzeit von einem Redakteur bearbeitet).

In unserem Szenario ist der Ordner pages/ eher ein views/ oder templates/ Ordner, und wir müssen in der Lage sein, jede Seite basierend auf den Daten zu rendern, die wir vom CMS erhalten .

Hallo zusammen! Wir haben gerade eine NPM-Bibliothek für eine Express-Architektur in Next.js gestartet, ohne einen Express-Server hinzuzufügen. Es könnte für Ihre Middleware-Herausforderungen hilfreich sein! Schau es dir bei Interesse an. https://github.com/oslabs-beta/connext-js

@sarapowers Ich werde mir das gleich

@runofthemill Zu diesem Zeitpunkt verwendet Connext die API-Routen von Next.js, sodass 9.0 die Mindestversion ist, die Sie benötigen. Wir würden es jedoch gerne eines Tages mit älteren Versionen kompatibel machen!

Hey @timneutkens - möchte die Diskussion hier nur mit einigen klärenden Punkten next-i18next in der Vergangenheit dazu getrieben wurde, einen benutzerdefinierten Server zu verwenden:

  1. Spracherkennung selbst, basierend auf Cookies/Headern/etc
  2. Weiterleitungen, basierend auf Sprache

Das zweite Problem wird von rewrites - wartet nur darauf, dass das Experiment landet.

Wir müssen jedoch weiterhin Spracherkennungs-Middleware für jede eingehende Frontend-Anfrage (und in einigen Fällen möglicherweise 302) ausführen. Wenn dieser RFC nicht mehr berücksichtigt wird, frage ich mich, ob Sie einen Vorschlag für die "Best Practice" haben, dies zu tun?

Ich habe https://github.com/isaachinman/next-i18next/pull/689 als erste Arbeitsidee zur Unterstützung von serverlosem i18n mit NextJs vorgestellt, und wir machen buchstäblich:

const middlewares = nextI18NextMiddleware(nextI18Next)
for (const middleware of middlewares) {
  await new Promise((resolve) => middleware(req, res, resolve))
}

In einem verpackten getInitialProps . Ist dies die Userland-Zukunft der Nicht-API-Middleware?

Der aktuelle Plan sieht vor, das Konzept der Sprachen / Spracherkennung in Next.js zu integrieren, damit wir es sowohl mit SSG als auch mit SSR zum Laufen bringen können und es in den meisten Fällen am Rande funktioniert. Dies ähnelt zB dem Vorschaumodus.

Ah, ich wusste nicht, dass das auf den Karten stand.

Vielleicht sehe ich naiverweise nicht, wie das das Problem der Lokalisierung in NextJs-Apps lösen oder sogar vereinfachen würde.

Die Spracherkennung selbst ist ein gelöstes Problem. Der eigentliche Trick bei universellen/NextJs-Apps besteht darin, die Spracherkennung in Verbindung mit dem gespeicherten Zustand über Cookies und dem potenziellen Zustand über das Routing (Locale-Unterpfade) zu handhaben.

Es gibt zwar Möglichkeiten, sich vollständig statischen Lösungen anzunähern, indem man eigenwillige Routing-Ansätze verfolgt, aber viele gültige Anwendungsfälle erfordern immer Middleware.

Der aktuelle Plan sieht vor, das Konzept der Sprachen / Spracherkennung in Next.js zu integrieren, damit wir es sowohl mit SSG als auch mit SSR zum Laufen bringen können und es in den meisten Fällen am Rande funktioniert. Dies ähnelt zB dem Vorschaumodus.

Können wir mehr Informationen dazu @timneutkens bekommen ? An welchen Aspekten von I18n wird Next.js beteiligt sein und an welchen nicht?

Kann noch keine Details teilen. Muss noch einen RFC dafür schreiben.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen