Node.js 指南(HTTP事务的剖析)

栏目: Node.js · 发布时间: 7年前

内容简介:本指南的目的是让你充分了解Node.js HTTP处理的过程,我们假设你在一般意义上知道HTTP请求的工作方式,无论语言或编程环境如何,我们还假设你对Node.js任何节点Web服务器应用程序在某些时候都必须创建Web服务器对象,这是通过使用传递给

HTTP事务的剖析

本指南的目的是让你充分了解Node.js HTTP处理的过程,我们假设你在一般意义上知道HTTP请求的工作方式,无论语言或编程环境如何,我们还假设你对Node.js EventEmittersStreams 有点熟悉,如果你对它们不太熟悉,那么值得快速阅读每个API文档。

创建服务器

任何节点Web服务器应用程序在某些时候都必须创建Web服务器对象,这是通过使用 createServer 完成的。

const http = require('http');

const server = http.createServer((request, response) => {
  // magic happens here!
});

传递给 createServer 的函数对于针对该服务器发出的每个HTTP请求都会调用一次,因此它被称为请求处理程序,实际上, createServer 返回的 Server 对象是一个 EventEmitter ,我们这里只是创建 server 对象的简写,然后稍后添加监听器。

const server = http.createServer();
server.on('request', (request, response) => {
  // the same kind of magic happens here!
});

当HTTP请求命中服务器时,node使用一些方便的对象调用请求处理函数来处理事务、 requestresponse ,我们很快就会讲到。

为了实际处理请求,需要在 server 对象上调用 listen 方法,在大多数情况下,你需要传递给 listen 的是你希望服务器监听的端口号,还有一些其他选项,请参阅API参考。

方法、URL和Headers

处理请求时,你可能要做的第一件事就是查看方法和URL,以便采取适当的措施,Node通过将方便的属性放在 request 对象上来使这相对轻松。

const { method, url } = request;

注意: request 对象是 IncomingMessage 的一个实例。

这里的 method 将始终是普通的HTTP方法/动作, url 是没有服务器、协议或端口的完整URL,对于典型的URL,这意味着包括第三个正斜杠后的所有内容。

Headers也不远,它们在自己的 request 对象中,被称为 headers

const { headers } = request;
const userAgent = headers['user-agent'];

这里需要注意的是,无论客户端实际发送它们的方式如何,所有headers都仅以小写字母表示,这简化了为任何目的解析headers的任务。

如果重复某些headers,则它们的值将被覆盖或以逗号分隔的字符串连接在一起,具体取决于header,在某些情况下,这可能会有问题,因此 rawHeaders 也可用。

请求体

收到 POSTPUT 请求时,请求体可能对你的应用程序很重要,获取body数据比访问请求headers更复杂一点,传递给处理程序的 request 对象实现了 ReadableStream 接口,就像任何其他流一样,可以在其他地方监听或传输此流,我们可以通过监听流的 'data''end' 事件来直接从流中获取数据。

每个 'data' 事件中发出的块是一个 Buffer ,如果你知道它将是字符串数据,那么最好的方法是在数组中收集数据,然后在 'end' ,连接并对其进行字符串化。

let body = [];
request.on('data', (chunk) => {
  body.push(chunk);
}).on('end', () => {
  body = Buffer.concat(body).toString();
  // at this point, `body` has the entire request body stored in it as a string
});

注意:这看起来有点单调乏味,而且在很多情况下确实如此,幸运的是,在 npm 上有像 concat-streambody 这样的模块可以帮助隐藏一些逻辑,在走这条路之前,要很好地了解正在发生的事情,这就是为什么你在这里!

关于错误的简单介绍

由于 request 对象是一个 ReadableStream ,它也是一个 EventEmitter ,发生错误时的行为与此类似。

request 流中的错误通过在流上发出 'error' 事件来呈现,如果你没有该事件的侦听器,则会抛出错误,这可能会导致Node.js程序崩溃。因此,你应该在请求流上添加 'error' 侦听器,即使你只是记录它并继续前进(虽然最好发送某种HTTP错误响应,稍后会详细介绍)。

request.on('error', (err) => {
  // This prints the error message and stack trace to `stderr`.
  console.error(err.stack);
});

还有其他方法可以处理这些错误,例如其他抽象和工具,但始终要注意错误可能并且确实会发生,并且你将不得不处理它们。

到目前为止我们已经得到了什么

此时,我们已经介绍了如何创建服务器,并从请求中获取方法、URL、headers和body,当我们将它们放在一起时,它可能看起来像这样:

const http = require('http');

http.createServer((request, response) => {
  const { headers, method, url } = request;
  let body = [];
  request.on('error', (err) => {
    console.error(err);
  }).on('data', (chunk) => {
    body.push(chunk);
  }).on('end', () => {
    body = Buffer.concat(body).toString();
    // At this point, we have the headers, method, url and body, and can now
    // do whatever we need to in order to respond to this request.
  });
}).listen(8080); // Activates this server, listening on port 8080.

如果我们运行此示例,我们将能够接收请求,但不会响应它们,实际上,如果你在Web浏览器中请求此示例,则你的请求将超时,因为没有任何内容被发送回客户端。

到目前为止,我们还没有涉及响应对象,它是 ServerResponse 的一个实例,它是一个 WritableStream ,它包含许多用于将数据发送回客户端的有用方法,接下来我们将介绍。

HTTP状态码

如果不设置它,响应中的HTTP状态码始终为 200 ,当然,并非每个HTTP响应都保证这一点,并且在某些时候你肯定希望发送不同的状态码,为此,你可以设置 statusCode 属性。

response.statusCode = 404; // Tell the client that the resource wasn't found.

还有其他一些快捷方式,我们很快就会看到。

设置响应Headers

Headers是通过一个名为 setHeader 的方便方法设置的。

response.setHeader('Content-Type', 'application/json');
response.setHeader('X-Powered-By', 'bacon');

在响应上设置headers时,大小写对其名称不敏感,如果重复设置标题,则设置的最后一个值是发送的值。

显式发送Header数据

我们已经讨论过的设置headers和状态码的方法假设你正在使用“隐式headers”,这意味着在开始发送body数据之前,你需要依赖node在正确的时间为你发送headers。

如果需要,可以将headers显式写入响应流,为此,有一个名为 writeHead 的方法,它将状态码和headers写入流。

response.writeHead(200, {
  'Content-Type': 'application/json',
  'X-Powered-By': 'bacon'
});

一旦设置了headers(隐式或显式),你就可以开始发送响应数据了。

发送响应体

由于 response 对象是 WritableStream ,因此将响应体写入客户端只需使用常用的流方法即可。

response.write('<html>');
response.write('<body>');
response.write('<h1>Hello, World!</h1>');
response.write('</body>');
response.write('</html>');
response.end();

流上的 end 函数也可以接收一些可选数据作为流上的最后一位数据发送,因此我们可以如下简化上面的示例。

response.end('<html><body><h1>Hello, World!</h1></body></html>');

注意:在开始向body写入数据块之前设置状态和headers很重要,这是有道理的,因为headers在HTTP响应中位于body之前。

关于错误的另一件事

response 流也可以发出 'error' 事件,在某些时候你也必须处理它,所有关于 request 流错误的建议仍然适用于此处。

把它放在一起

现在我们已经了解了如何进行HTTP响应,让我们把它们放在一起,在前面的示例的基础上,我们将创建一个服务器,用于发回用户发送给我们的所有数据,我们将使用 JSON.stringify 将该数据格式化为JSON。

const http = require('http');

http.createServer((request, response) => {
  const { headers, method, url } = request;
  let body = [];
  request.on('error', (err) => {
    console.error(err);
  }).on('data', (chunk) => {
    body.push(chunk);
  }).on('end', () => {
    body = Buffer.concat(body).toString();
    // BEGINNING OF NEW STUFF

    response.on('error', (err) => {
      console.error(err);
    });

    response.statusCode = 200;
    response.setHeader('Content-Type', 'application/json');
    // Note: the 2 lines above could be replaced with this next one:
    // response.writeHead(200, {'Content-Type': 'application/json'})

    const responseBody = { headers, method, url, body };

    response.write(JSON.stringify(responseBody));
    response.end();
    // Note: the 2 lines above could be replaced with this next one:
    // response.end(JSON.stringify(responseBody))

    // END OF NEW STUFF
  });
}).listen(8080);

Echo服务器示例

让我们简化前面的示例来进行一个简单的echo服务器,它只是在响应中发送请求中收到的任何数据,我们需要做的就是从请求流中获取数据并将该数据写入响应流,类似于我们之前所做的。

const http = require('http');

http.createServer((request, response) => {
  let body = [];
  request.on('data', (chunk) => {
    body.push(chunk);
  }).on('end', () => {
    body = Buffer.concat(body).toString();
    response.end(body);
  });
}).listen(8080);

现在让我们调整一下,我们只想在以下条件下发送echo:

POST

在任何其他情况下,我们只想响应 404

const http = require('http');

http.createServer((request, response) => {
  if (request.method === 'POST' && request.url === '/echo') {
    let body = [];
    request.on('data', (chunk) => {
      body.push(chunk);
    }).on('end', () => {
      body = Buffer.concat(body).toString();
      response.end(body);
    });
  } else {
    response.statusCode = 404;
    response.end();
  }
}).listen(8080);

注意:通过这种方式检查URL,我们正在做一种“路由”的形式,其他形式的路由可以像 switch 语句一样简单,也可以像 express 这样的整个框架一样复杂,如果你正在寻找可以进行路由的东西,请尝试使用 router

现在让我们来简化一下吧,请记住, request 对象是 ReadableStreamresponse 对象是 WritableStream ,这意味着我们可以使用 pipe 将数据从一个引导到另一个,这正是我们想要的echo服务器!

const http = require('http');

http.createServer((request, response) => {
  if (request.method === 'POST' && request.url === '/echo') {
    request.pipe(response);
  } else {
    response.statusCode = 404;
    response.end();
  }
}).listen(8080);

我们还没有完成,正如本指南中多次提到的,错误可以而且确实会发生,我们需要处理它们。

为了处理请求流上的错误,我们将错误记录到 stderr 并发送 400 状态码以指示 Bad Request ,但是,在实际应用程序中,我们需要检查错误以确定正确的状态码和消息是什么,与通常的错误一样,你应该查阅错误文档。

在响应中,我们只是将错误记录到 stderr

const http = require('http');

http.createServer((request, response) => {
  request.on('error', (err) => {
    console.error(err);
    response.statusCode = 400;
    response.end();
  });
  response.on('error', (err) => {
    console.error(err);
  });
  if (request.method === 'POST' && request.url === '/echo') {
    request.pipe(response);
  } else {
    response.statusCode = 404;
    response.end();
  }
}).listen(8080);

我们现在已经介绍了处理HTTP请求的大部分基础知识,此时,你应该能够:

  • 使用请求处理程序函数实例化HTTP服务器,并让它侦听端口。
  • request 对象中获取headers、URL、方法和body数据。
  • 根据 request 对象中的URL和/或其他数据做出路由决策。
  • 通过 response 对象发送headers、HTTP状态码和body数据。
  • request 对象和 response 对象管道数据。
  • 处理 requestresponse 流中的流错误。

从这些基础知识中,可以构建用于许多典型用例的Node.js HTTP服务器,这些API提供了许多其他功能,因此请务必阅读有关 EventEmittersStreamsHTTP 的API文档。

上一篇:Node.js中的定时器


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Algorithmic Beauty of Plants

The Algorithmic Beauty of Plants

Przemyslaw Prusinkiewicz、Aristid Lindenmayer / Springer / 1996-4-18 / USD 99.00

Now available in an affordable softcover edition, this classic in Springer's acclaimed Virtual Laboratory series is the first comprehensive account of the computer simulation of plant development. 150......一起来看看 《The Algorithmic Beauty of Plants》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具