Node中的HTTP

来源:互联网 发布:linux chmod nobody 编辑:程序博客网 时间:2024/05/29 16:02
来自对《了不起的Node.js》一书的学习

HTTP协议

  1. 超文本传输协议,又称为HTTP,是一种Web协议。
  2. HTTP协议构建在请求和响应的概念上,对应在Node.js中就是由http.ClientRequest和http.ServerResponse这个两个构造器构造出来的对象(Node.js v6.2.0)。
  3. HTTP协议在请求和响应消息前使用头信息(header)来描述不同的消息内容。
  4. 发送内容的类型(type)由头信息中的Content-Type头信息来标注,Web页面会分发许多不同类型的内容:文本(text)、HTML、XML、JSON、PNG以及JPEG图片,等等。
  5. 在Node.js中,Node会默认在响应消息的头信息中加入Transfer-Encoding和Connection。
  6. Transfer-Encoding头信息的默认值为chunked,主要的原因是Node天生的异步机制,这样响应就可以逐步产生。
      一般情况下,HTTP的Header包含Content-length域来指明报文体的长度。有时服务生成HTTP回应是无法确定消息大小的,比如大文件的下载,或者后台需要复杂的逻辑才能全部处理页面的请求,这时就需要实时生成消息长度,服务一般使用chunked编码。
  7. 在Node.js中TCP服务器和HTTP服务器的实现,都调用了createServer方法,并且当客户端连入时都会执行一个回调函数。不同的是,回调函数中的对象的类型。在net服务器中(TCP服务器),是个连接(connection)对象,而在HTTP服务器中,则是请求和响应对象。
      之所以会这样,原因有两个。
      1)HTTP服务器是更高层的API,提供了控制和HTTP协议相关的一些功能。实际上Node.js为我们封装了请求消息和响应消息对象。
      2)同时也是一个更为重要的原因是,浏览器在访问站点时不会就只用一个连接。
      默认情况下,Node会告诉浏览器始终保持连接,通过它发送更多的请求。这是通过此前我们看到的Connection头信息中的keep-alive值来通知浏览器的。为了提高性能(因为浏览器不想浪费时间去重新建立和关闭TCP连接),这样做通常是对的。不过,我们也可以调用writeHead方法,传递一个不同的值,如Close,来将其重写掉。

一个简单的Web服务器

  1. 创建模块:npm init。
{  "name": "http-form",  "version": "0.0.1",  "description": "An HTTP server that process forms",  "main": "index.js",  "scripts": {    "test": "echo \"Error: no test specified\" && exit 1"  },  "author": "",  "license": "ISC"}

初始化项目。
2. 创建server.js,向客户端输出一个表单:

var http = require('http');http.createServer(function(req, res) {    // console.log(req.url);    res.writeHead(200, {'Content-Type': 'text/html'});    res.end([        '<form method="POST" action="/url">',        '<h1>My form</h1>',        '<fieldset>',        '<label>Personal information</label>',        '<p>What is your name?</p>',        '<input type="text" name="name">',        '<p><button>Submit</button></p>',        '</form>'        ].join(''));}).listen(3000);

其中,表单提交的地址为/url,同时采用POST方法。
3. 使用 node server.js 来运行服务器。
4. 在浏览器中访问:127.0.0.1:3000,我们会在浏览器中看到输出来的表单。
页面-表单
页面显示的结果。
5. 为了实现接收表单提交的数据,我们来将上述server.js代码中的console.log这一行代码注释掉,在重新运行服务器,看看在命令行中会出现什么。
输出结果
  我们在浏览器中修改url地址呢?在127.0.0.1:300后面加上 /url ,我们想访问这样的地址,会出现什么样的结果呢?
请求结果
  看,我们请求的 /url 地址被输出显示出来了(有点莫名其妙,我们先不管——居然这样访问,不会404报错,而是被服务器正确接收,在server.js的回调方法中打印出用户访问的相对地址),同时在浏览器中显示的结果还是同刚才访问的页面一样。
  那么我们就可以在server.js中的回调方法中判断当前请求的地址,来对应是否在form表单请求的地址,如果是,则对该请求进行相应的处理。
6. 在server.js中需要对请求对象上的url属性进行检测。server.js的代码如下所示:

var http = require('http');http.createServer(function(req, res) {    // console.log(req.url);    if('/' == req.url) {        res.writeHead(200, {'Content-Type': 'text/html'});        res.end([            '<form method="POST" action="/url">',            '<h1>My form</h1>',            '<fieldset>',            '<label>Personal information</label>',            '<p>What is your name?</p>',            '<input type="text" name="name">',            '<p><button>Submit</button></p>',            '</form>'            ].join(''));        } else if('/url' == req.url) {        res.writeHead(200, {'Content-Type': 'text/html'});        res.end('You sent a <em>' + req.method + '</em> request.');    }}).listen(3000);

  再次运行node server.js,刷新页面看看,这次提交表单会有什么变化吧。
7. 这会能猜到结果了吧,当我们直接提交表单后会跳转 /url 链接,此时服务器接收到发现请求是 /url 地址,就进行了相应的处理,返回相应的内容被浏览器接收,最后给浏览器显示出来。
8. 那么我们现在在浏览器访问其他地址呢,会发现浏览器会请求很久很久,最后提示我们:
请求结果
  这是因为我们在服务器中没有对其他地址进行响应的操作。
  注:Node.js会将主机名后所有的内容都放在(req.)url属性中。
9. 接下来我们需要接收form表单提交过来的数据。需要注意的是:请求消息也可以包含Content-Type头信息。就像响应消息有Content-Type头信息来告诉浏览器它返回了什么数据一样,浏览器发送请求是也可以告诉服务器我发送了什么类型数据给你(服务器)了。server.js代码如下:

var http = require('http');http.createServer(function(req, res) {    // console.log(req.url);    if('/' == req.url) {        res.writeHead(200, {'Content-Type': 'text/html'});        res.end([            '<form method="POST" action="/url">',            '<h1>My form</h1>',            '<fieldset>',            '<label>Personal information</label>',            '<p>What is your name?</p>',            '<input type="text" name="name">',            '<p><button>Submit</button></p>',            '</form>'            ].join(''));        } else if('/url' == req.url && 'POST' == req.method) {        var body = '';        req.on('data', function(chunk) {            body += chunk;        });        req.on('end', function() {            res.writeHead(200, {'Content-Type': 'text/html'});            // res.end('You sent a <em>' + req.method + '</em> request.');            res.end('<p>Content-Type: ' + req.headers['content-type'] + '</p>'                + '<p>Data:</p><pre>' + body + '</pre>');        });    }}).listen(3000);

  运行结果如下:
运行结果
  结果显示:提交的数据Content-Type,即数据格式为键值对字符串的形式,或者说是一个查询字符串(key1=value1&key2=value2&…)。我们需要对该字符串进行解析,生成我们想要的对象,便于操作。好在Node.js为我们提供了一个称为querystring的模块,方便地对这类字符串进行解析。
  querystring模块将一个字符串解析成一个对象。这个解析处理方法和Node解析headers消息的方式类似,Node将HTTP请求数据中的headers信息从字符串解析成一个方便处理的headers对象。
10. 使用querystring的parse方法对请求内容进行解析,然后从解析生成的对象中获取name值,并将其展示给用户。server.js部分代码修改如下:
  引入querystring模块:

var qs = require('querystring');

  修改req.end中的回调:

req.on('end', function() {            res.writeHead(200, {'Content-Type': 'text/html'});            // res.end('You sent a <em>' + req.method + '</em> request.');            /*res.end('<p>Content-Type: ' + req.headers['content-type'] + '</p>'                + '<p>Data:</p><pre>' + body + '</pre>');*/            res.end('<p>Your name is <b>' + qs.parse(body).name + '</b></p>');        });

  重新运行后正确显示结果。
11. 如果URL没有匹配到任何判断条件,那么服务器将会一直没有响应,浏览器一直都处在挂起的状态。要解决这样的问题,我们可以在服务器不知道如何处理请求时,发送404(Not Found)状态码给客户端。server.js部分代码修改如下:

} else {    res.writeHead(404);    res.end('Not Found');}

  这个时候,我们才真正完成了第一个HTTP Web服务器!!!

0 0
原创粉丝点击