网络编程:构建 HTTP服务

编程入门 行业动态 更新时间:2024-10-15 22:30:18

<a href=https://www.elefans.com/category/jswz/34/1768814.html style=网络编程:构建 HTTP服务"/>

网络编程:构建 HTTP服务

1. http 模块

Node的 http 模块包含对HTTP处理的封装。在Node中,HTTP服务继承自TCP服务器( net 模块),它能够与多个客户端保持连接,由于其采用事件驱动的形式,并不为每一个连接创建额外的线程或进程,保持很低的内存占用,所以能实现高并发。HTTP服务与TCP服务模型有区别的地方在于,在开启 keepalive 后,一个TCP会话可以用于多次请求和响应。TCP服务以 connection为单位进行服务,HTTP服务以 request 为单位进行服务。 http 模块即是将 connection 到 request 的过程进行了封装,示意图如下图:

                      

1.1. http报文

我们用一个小例子来展示http的一个完整报文:

编写最简单的http服务程序并启动:http_server.js

var http = require('http');
http.createServer(function (req, res) {res.writeHead(200, {'Content-Type': 'text/plain'});res.end('Hello World\n');
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');

然后使用curl工具进行请求:

xiao@uXiao:~/nodejs/深入浅出nodejs/chapter7$ curl -v http://127.0.0.1:1337/
*   Trying 127.0.0.1:1337...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 1337 (#0)
> GET / HTTP/1.1
> Host: 127.0.0.1:1337
> User-Agent: curl/7.65.3
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Content-Type: text/plain
< Date: Thu, 02 Jan 2020 09:35:38 GMT
< Connection: keep-alive
< Transfer-Encoding: chunked
< 
Hello World
* Connection #0 to host 127.0.0.1 left intact

从上述信息中我们可以看到这次网络通信的报文信息分为四个部分,

第一部分内容为经典的TCP的3次握手过程,如下所示:

* About to connect() to 127.0.0.1 port 1337 (#0)
* Trying 127.0.0.1...
* connected
* Connected to 127.0.0.1 (127.0.0.1) port 1337 (#0)

第二部分是在完成握手之后,客户端向服务器端发送请求报文,如下所示:

GET / HTTP/1.1
User-Agent: curl/7.24.0 (x86_64-apple-darwin12.0) libcurl/7.24.0 OpenSSL/0.9.8r zlib/1.2.5
Host: 127.0.0.1:1337
Accept: */*

第三部分是服务器端完成处理后,向客户端发送响应内容,包括响应头和响应体,如下所示:

< HTTP/1.1 200 OK
< Content-Type: text/plain
< Date: Sat, 06 Apr 2013 08:01:44 GMT
< Connection: keep-alive
< Transfer-Encoding: chunked
<
Hello World

最后部分是结束会话的信息,如下所示:

* Connection #0 to host 127.0.0.1 left intact
* Closing connection #0

从上述的报文信息中可以看出HTTP的特点,它是基于请求响应式的,以一问一答的方式实现服务,虽然基于TCP会话,但是本身却并无会话的特点。

2. 构建示例

下面模拟实现一个简单的文件服务器:http_file_server.js

//实现一个静态文件服务器
var fs = require('fs');
var http = require('http');
var url = require('url');
//创建一个服务器
http.createServer( function(req,res) {if (req.url != "/favicon.ico"){var urlObj = url.parse(req.url,true,false);console.log(urlObj.pathname);fs.readFile('.' + urlObj.pathname,  function(err,data) {if (err){res.writeHead(404, {'Content-Type': 'text/plain'});res.end(JSON.stringify(err));return;}console.log(data.toString());//将文件的内容写入res响应对象res.writeHead(200, {'Content-Type': 'text/plain'});res.end(data);});}
}).listen(8080);

在http_file_server.js同一目录下准备好一个测试文件test_json.json,然后编写客户端程序test_http_client.js :

var http = require('http');
var options = {hostname: '127.0.0.1',port: 8080,path: '/test_json.json',method: 'GET'
};
var req = http.request(options, function(res) {console.log('STATUS: ' + res.statusCode);console.log('HEADERS: ' + JSON.stringify(res.headers));res.setEncoding('utf8');res.on('data', function (chunk) {console.log(chunk);});
});req.end();

启动服务端程序,然后运行客户端,输出为:

xiao@uXiao:~/nodejs/深入浅出nodejs/chapter7$ node test_http_client.js 
STATUS: 200
HEADERS: {"content-type":"text/plain","date":"Thu, 02 Jan 2020 10:28:03 GMT","connection":"close","transfer-encoding":"chunked"}
{"rule":{"namespace":"strategy","name":"test_exp_1496234234223400","version":0,"last_modify_time":1434234236819000,"log_rate":1023300,"schema_version":"hello_world!"}}

2.1 服务端分析

报文头:

HEADERS: {"content-type":"text/plain","date":"Thu, 02 Jan 2020 10:28:03 GMT","connection":"close","transfer-encoding":"chunked"}

影 响 响 应 报 文 头 部 信 息 的 API 为 res.setHeader() 和 res.writeHead() 。在上述示例中:res.writeHead(404, {'Content-Type': 'text/plain'});其分为 setHeader() 和 writeHead() 两个步骤。它在 http 模块的封装下,实际生成如下报文:

< HTTP/1.1 200 OK
< Content-Type: text/plain

我们可以调用 setHeader 进行多次设置,但只有调用 writeHead 后,报头才会写入到连接中。除此之外, http 模块会自动帮你设置一些头信息。
报文体部分:

报文体部分则是调用 res.write() 和 res.end() 方法实现,后者与前者的差别在于 res.end() 会先调用 write() 发送数据,然后发送信号告知服务器这次响应结束,响应结果如下所示:

响应结束后,HTTP服务器可能会将当前的连接用于下一个请求,或者关闭连接。值得注意
的是,报头是在报文体发送前发送的,一旦开始了数据的发送, writeHead() 和 setHeader() 将不
再生效。这由协议的特性决定。
另外,无论服务器端在处理业务逻辑时是否发生异常,务必在结束时调用 res.end() 结束请
求,否则客户端将一直处于等待的状态。当然,也可

更多推荐

网络编程:构建 HTTP服务

本文发布于:2024-03-09 21:35:41,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1726163.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:网络编程   HTTP

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!