来自对《了不起的Node.js》一书的学习
HTTP协议
- 超文本传输协议,又称为HTTP,是一种Web协议。
- HTTP协议构建在请求和响应的概念上,对应在Node.js中就是由http.ClientRequest和http.ServerResponse这个两个构造器构造出来的对象(Node.js v6.2.0)。
- HTTP协议在请求和响应消息前使用头信息(header)来描述不同的消息内容。
- 发送内容的类型(type)由头信息中的Content-Type头信息来标注,Web页面会分发许多不同类型的内容:文本(text)、HTML、XML、JSON、PNG以及JPEG图片,等等。
- 在Node.js中,Node会默认在响应消息的头信息中加入Transfer-Encoding和Connection。
- Transfer-Encoding头信息的默认值为chunked,主要的原因是Node天生的异步机制,这样响应就可以逐步产生。
一般情况下,HTTP的Header包含Content-length域来指明报文体的长度。有时服务生成HTTP回应是无法确定消息大小的,比如大文件的下载,或者后台需要复杂的逻辑才能全部处理页面的请求,这时就需要实时生成消息长度,服务一般使用chunked编码。 - 在Node.js中TCP服务器和HTTP服务器的实现,都调用了createServer方法,并且当客户端连入时都会执行一个回调函数。不同的是,回调函数中的对象的类型。在net服务器中(TCP服务器),是个连接(connection)对象,而在HTTP服务器中,则是请求和响应对象。
之所以会这样,原因有两个。
1)HTTP服务器是更高层的API,提供了控制和HTTP协议相关的一些功能。实际上Node.js为我们封装了请求消息和响应消息对象。
2)同时也是一个更为重要的原因是,浏览器在访问站点时不会就只用一个连接。
默认情况下,Node会告诉浏览器始终保持连接,通过它发送更多的请求。这是通过此前我们看到的Connection头信息中的keep-alive值来通知浏览器的。为了提高性能(因为浏览器不想浪费时间去重新建立和关闭TCP连接),这样做通常是对的。不过,我们也可以调用writeHead方法,传递一个不同的值,如Close,来将其重写掉。
一个简单的Web服务器
- 创建模块:npm init。
初始化项目。
2. 创建server.js,向客户端输出一个表单:
其中,表单提交的地址为/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的代码如下所示:
再次运行node server.js,刷新页面看看,这次提交表单会有什么变化吧。
7. 这会能猜到结果了吧,当我们直接提交表单后会跳转 /url 链接,此时服务器接收到发现请求是 /url 地址,就进行了相应的处理,返回相应的内容被浏览器接收,最后给浏览器显示出来。
8. 那么我们现在在浏览器访问其他地址呢,会发现浏览器会请求很久很久,最后提示我们:
这是因为我们在服务器中没有对其他地址进行响应的操作。
注:Node.js会将主机名后所有的内容都放在(req.)url属性中。
9. 接下来我们需要接收form表单提交过来的数据。需要注意的是:请求消息也可以包含Content-Type头信息。就像响应消息有Content-Type头信息来告诉浏览器它返回了什么数据一样,浏览器发送请求是也可以告诉服务器我发送了什么类型数据给你(服务器)了。server.js代码如下:
运行结果如下:
结果显示:提交的数据Content-Type,即数据格式为键值对字符串的形式,或者说是一个查询字符串(key1=value1&key2=value2&…)。我们需要对该字符串进行解析,生成我们想要的对象,便于操作。好在Node.js为我们提供了一个称为querystring的模块,方便地对这类字符串进行解析。
querystring模块将一个字符串解析成一个对象。这个解析处理方法和Node解析headers消息的方式类似,Node将HTTP请求数据中的headers信息从字符串解析成一个方便处理的headers对象。
10. 使用querystring的parse方法对请求内容进行解析,然后从解析生成的对象中获取name值,并将其展示给用户。server.js部分代码修改如下:
引入querystring模块:
修改req.end中的回调:
重新运行后正确显示结果。
11. 如果URL没有匹配到任何判断条件,那么服务器将会一直没有响应,浏览器一直都处在挂起的状态。要解决这样的问题,我们可以在服务器不知道如何处理请求时,发送404(Not Found)状态码给客户端。server.js部分代码修改如下:
这个时候,我们才真正完成了第一个HTTP Web服务器!!!