朴灵大师的书确实不错,让我受益非浅。
个人理解,仅做参考。
构建http服务
在Web领域,大多编程语言需要专门的Web服务器作为容器,如ASP、ASP.NET需要IIS,PHP需要搭载Apache或Nginx环境,JSP需要Tomcat。而node提供了http模块,基于TCP,内建了HTTP服务,只需几行代码就可构建服务器。如下:
var http = require('http');
http.createServer(function(req,res) {
console.log('hello world. req.url = ' + req.url);
res.writeHead(200,{'Content-Type':'text/plain'});
res.end('Hello world\n');
}).listen(1337,'127.0.0.1');
console.log('Sever running at http://127.0.0.1:1337/');
1、HTTP
启动服务器之后,获取报文
$ curl -v Http://127.0.0.1:1337/
//第一部分:链接部分
* timeout on name lookup is not supported
* Trying 127.0.0.1...
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* 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.44.0
> Accept: */*
>
//第三部分:服务器端完成处理之后,向客户端发送的响应内容,包括<开头的响应头和输出的Hello world 响应体。
< HTTP/1.1 200 OK
< Content-Type: text/plain
< Date: Sun, 20 Dec 2015 07:21:43 GMT
< Connection: keep-alive
< Transfer-Encoding: chunked
<
{ [22 bytes data]
100 12 0 12 0 0 750 0 --:--:-- --:--:-- --:--:-- 12000
Hello world
//第四部分:结束回话
* Connection #0 to host 127.0.0.1 left intact
通过报文可以看出HTTP的特点,他是基于请求响应式的,以一问一答的方式实现服务,虽然基于TCP会话,但是本身却没有会话的特点。
- 从协议的角度来说,现在的应用,如浏览器,其实是一个HTTP代理,用户的行为将通过它转换为HTTP请求报文发送给服务器端,服务器端在处理完请求后,发送响应报文给代理,代理在解析报文之后,将用户需要的内容(通常是报文体)呈现在界面上。*
简而言之,HTTP服务只做两件事:处理HTTP请求,发送HTTP响应。
- 无论是HTTP请求报文还是HTTP响应报文,都包含:报文头和报文体
2、http模块
HTTP请求
- 报文第二部分中的报文头通过http_parser进行解析,解析之后为:
req.method:'GET'
req.url: '/'
req.httpVersion: 1.1
headers: {//Key : Value 格式
'use-agent': 'curl/7.44.0'
host: '127.0.0.1:1337'
accept: '*/*'
}
此时cookie为:req.headers.cookie
cookie格式为key=value;key2=value形式
什么是Cookie、Session
- Cookie:HTTP是无状态的协议,但现实中的业务处理需要一定的状态,否者就无法区分不同的用户。比如说无需登录京东就可以添加购物车,你每一次添加的物品(多次请求)都到了同一个购物车。这就需要使用Cookie(存在于报文中)来标识和认证同一个账户。(前后端都可以操作Cookie)
- Cookie在浏览器和服务器的协作处理分下面几步
1、服务器向浏览器发送Cookie
2、浏览器将Cookie保存
3、之后每次浏览器都会想服务器发送Cookie - Session:由于在前后端都可以操作Cookie,所以有时使用Cookie是不安全的。比如需要更具Cookie中的isVIP字段来判断业务逻辑,但是前端可以篡改它来达到伪造的目的。而Session只保存在后端,对前端不可见,因此对于数据敏感的操作,就需要用到Session。(Session有效期限短)
- 基于Cookie来实现用户与数据的映射:服务器生成Session口令,传递Cookie,通过Cookie口令与Session口令来实现用户与数据的映射。一旦篡改了Cookie口令,就无法完成映射。并且Session口令过期时间短,之后再生成新的口令,这也是为什么登陆京东一段时间不操作就需要重新登陆。
基础中间件cookie-parser、实现:
var parseCookie = function (cookie) {
var cookies = {};
if(!cookie) {
return cookies;
}
var list = cookie.split(';');
for (var i = 0; i < list.length; i++) {
var pair = list[i].split('=');
cookies[pair[0].trim()] = pair[1];
}
return cookies;
}
//挂载到req对象上
//req.cookies = parseCookie(req.headers.cookie);
- 报文体抽象为一个只读对象流,如果业务逻辑需要读取报文体中的数据,需要在数据流结束之后才能操作
function (req,res) {
//console.log(req.headers);
var buffers = [];
req.on('data', function (trunk) {
buffers.push(trunk);
}).on('end', function () {
var buffers = Buffers.concat(buffers);
// TODO
res.end('Hello world');
})
}
HTTP响应
- 报文头:res.setHeader()和res.writeHeader()
可以调用setHeader进行多次设置,但只有调用了writeHead之后,报头才会写入链接中。 - 报文体:res.write()和res.end()
它们的区别在于res.end()会先调用res.write()发送数据,之后通知服务器这次响应结束。,
HTTP服务的事件
3、HTTP客户端
HTTP客户端原理与服务器端相同。HTTP客户端是服务器端服务模型的另一部分,处于HTTP的另一端,在整个报文的参与中,报文头和报文体由它产生。同时http模块提供了一个底层API:http.request(options, connect),用于构建HTTP客户端,如下:
var http = require('http');
var options = {
hostname: '127.0.0.1',
port: 1337,
path: '/',
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();
- 开启服务器后运行它,作用相当于 curl -v Http: //127.0.0.1:1337/。
参数请求:
host: 域名或IP 默认localhost
hosename: 服务器名称
port: 默认 80
localAddress:
socketPath: Domain套接字路径
method:
path:
headers:
auth: Basic认证