Zurück zum Blog

Folgen und abonnieren

Nur auf Englisch verfügbar

Diese Seite ist momentan nur auf Englisch verfügbar. Wir entschuldigen uns für die Unannehmlichkeiten. Bitte besuchen Sie diese Seite später noch einmal.

HTTP-Schnittstellen im Node.js Stil für Compute

Katsuyuki Omuro

Senior Software Engineer, Developer Relations, Fastly

Unsere Compute JavaScript Plattform bietet Request- und Response-Objekte, die jedoch auf dem Fetch Standard basieren und nicht auf den req- und res-Objekten, die traditionell in Node.js Programmen verwendet werden. Wenn Sie ein für Node.js entwickeltes Programm nutzen, das Sie auf Compute umstellen möchten, oder wenn eine Bibliothek, die Sie verwenden möchten, für Node entwickelt wurde, steht Ihnen unsere neue Open Source Bibliothek http-compute-js zur Verfügung.

Lange Zeit hat Node.js die Objekte IncomingMessage und ServerResponse zur Verfügung gestellt, die Anfragen an und Antworten von einem Webserver darstellen. Diese Objekte entsprechen nicht den Objekten Request und Response, die durch den modernen Fetch Standard definiert und durch JavaScript in Compute@Edge implementiert wurden. Obwohl Fetch in neueren Versionen von Node.js nativ unterstützt wird, ist der meiste derzeitige Node.js Code nicht auf Fetch ausgelegt.

Mit http-compute-js wollen wir Entwicklern Objekte zur Verfügung stellen, die die vertraute Node.js-kompatible Schnittstelle aufweisen, sodass Sie oder eine Bibliothek, die Sie verwenden möchten, damit interagieren können.

http-Objekte im Node.js Stil in Compute

Schauen Sie sich das an:

import http from '@fastly/http-compute-js';

const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({
    data: 'Hello World!'
  }));
});

server.listen();

Wenn Sie die import-Anweisung am Anfang nicht sehen würden, könnten Sie denken, dass dies ein normales Node.js Programm ist. Die createServer-Funktion akzeptiert einen Event Handler, dem ein Callback übergeben wird, dessen Argumente wie in einem Node.js Programm verwendet werden können.

req ist ein IncomingMessage-Objekt und seine lesbareStreaming-Schnittstelle ist mit dem Body Stream der Compute Anforderung verbunden. Als solches können Sie mit den Standard-Stream-Mechanismen wie on('data') und on('end') oder durch Piping zu einem anderen Stream oder mittels Bibliotheken wie parse-body daraus lesen. Sie können auch die Header und andere Informationen lesen, wie Sie es in Node.js tun würden.

res ist ein ServerResponse-Objekt, dessen beschreibbare Streaming-Schnittstelle mit einem In-Memory-Puffer verdrahtet ist. Schreiben Sie normal mit res.write() oder res.end() oder per Pipe mit res.pipe(). Sie können auch Header und Statuscode auf die gleiche Weise wie in Node.js setzen.

Hier ist ein etwas komplexeres Beispiel, das einige dieser Funktionen zeigt:

import http from '@fastly/http-compute-js';

const server = http.createServer(async (req, res) => {
  // Get URL, method, headers, and body from req
  const url = req.url;
  const method = req.method;
  const headers = {};
  for (let [key, value] of Object.entries(req.headers)) {
    if(!Array.isArray(value)) {
      value = [String(value)];
    }
    headers[key] = value.join(', ');
  }
  let body = null;
  if (method !== 'GET' && method !== 'HEAD') {
    // Reading data out of a stream.Readable 
    body = await new Promise(resolve => {
      const data = [];
      req.on('data', (chunk) => {
        data.push(chunk);
      });
      req.on('end', () => {
        resolve(data.join(''));
      });
    });
  }

  // Write output to res
  res.setHeader('Content-Type', 'application/json');
  res.statusCode = 200;
  res.write(JSON.stringify({
    url,
    method,
    headers,
    body,
  }));
  res.end();
});

server.listen();

Beachten Sie, dass der an createServer übergebene Callback async ist. Die Antwort wird nach dem „await“ erstellt, aber der Handler ist in der Lage, auf res.end() zu warten, bevor er eine Response erstellt und sie über den zugrunde liegenden Compute Event Handler fetch zurücksendet.

Polyfills helfen uns bei der richtigen Anwendung

Damit sich http-compute-js so verhält, wie es erwartet wird, haben wir uns entschlossen, bestehende, gut getestete Polyfills für einige der zugrunde liegenden Teile zu verwenden, zum Beispiel für Streaming und Pufferung. Compute JavaScript Programme verwenden Webpack für die Bündelung zu einem Webworker, wo wir diese Polyfills hinzufügen können. Um http-compute-js zu verwenden, müssen Sie daher ein paar Änderungen an der Datei webpack.config.js vornehmen, die mit einem JavaScript Compute Projekt geliefert wird. 

Fügen Sie das folgende webpack.ProvidePlugin() zum Plugins Array und die folgenden Elemente zu den Abschnitten „alias“ und „fallback“ hinzu, indem Sie die Eigenschaften „resolve“, „alias“ und „fallback“ nach Bedarf erstellen. 

module.exports = {
  /* ...other config... */
  plugins: [
    new webpack.ProvidePlugin({
      Buffer: [ 'buffer', 'Buffer' ],
      process: 'process',
      setTimeout: [ 'timeout-polyfill', 'setTimeout' ],
      clearTimeout: [ 'timeout-polyfill', 'clearTimeout' ],
    }),
  ],
  resolve: {
    alias: {
      'timeout-polyfill': require.resolve('@fastly/http-compute-js/dist/polyfill'),
    },
    fallback: {
      'buffer': require.resolve('buffer/'),
      'process': require.resolve('process/browser'),
      'stream': require.resolve('stream-browserify'),
    }
  },
};

Sobald Sie diese Einstellungen vorgenommen haben, werden die Beispiele in diesem Beitrag so funktionieren, wie Sie es in Node.js erwarten würden. Wir hoffen, die Unterstützung für setTimeout in Compute bald ausliefern zu können, sodass wir vielleicht auch irgendwann die Anzahl der Polyfills reduzieren können.

Manuelle Instanziierung von req und res

Manchmal müssen Sie Request- und Response-Objekte im Node.js Stil nur für einige Teile Ihres Programms verwenden. Oder vielleicht möchten Sie einmalig eine Funktion aufrufen, die mit diesen Objekten arbeitet. Für diese Fälle stellen wir Dienstprogramme zur Verfügung, die Ihnen dabei helfen, zwischen den in Compute verwendeten Objekten Request und Response und ihren Node.js-kompatiblen Gegenstücken hin- und herzuspringen.

/// <reference types='@fastly/js-compute' />
import { toReqRes, toComputeResponse } from '@fastly/http-compute-js';

addEventListener('fetch', (event) => event.respondWith(handleRequest(event)));
async function handleRequest(event) {
  // Create Node.js-compatible req and res from event.request
  const { req, res } = toReqRes(event.request);

  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({
    data: 'Hello World!',
    url: req.url,
  }));

  // Create a Compute@Edge Response object based on res, and return it
  const response = await toComputeResponse(res);
  return response;
}

Dieses Beispiel zeigt, wie einfach es ist, während eines Fetch Handlers Node-kompatible req und res zu erstellen, und wie man sie in ein Compute Response-Objekt umwandelt und zurückgibt.

Noch mehr Code auf der Edge ausführen

Das Internet als programmierbare Plattform entwickelt sich ständig weiter. Wir sind stolz darauf, in diesem Bereich Experte zu sein, und wir wollen, dass Compute auch weiterhin eine attraktive Plattform für Entwickler ist.

Wir wissen, dass diese fortwährende Entwicklung bedeutet, dass sich alles ständig verändert. Deshalb arbeiten wir unermüdlich an der Entwicklung von Tools, die Sie in die Lage versetzen, noch mehr Code auf der Edge auszuführen und schneller dafür zu entwickeln, während wir gleichzeitig den Einsatz einer breiteren Palette von Tools ermöglichen wollen. Wir sind gespannt zu sehen, was Sie mit diesem Tool erstellen werden, und erfahren gerne, was Sie mit diesem und unseren anderen Tools bereits geschaffen haben. Melden Sie sich bei uns auf Twitter und teilen Sie Ihre Erfahrung!