1019_Node中的HTTP

来自对《了不起的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。
{
  "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"
}
1
2
3
4
5
6
7
8
9
10
11
初始化项目。
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);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
其中,表单提交的地址为/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);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
再次运行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);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
运行结果如下:
 
结果显示:提交的数据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');
1
修改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>');
        });
1
2
3
4
5
6
7
重新运行后正确显示结果。
11. 如果URL没有匹配到任何判断条件,那么服务器将会一直没有响应,浏览器一直都处在挂起的状态。要解决这样的问题,我们可以在服务器不知道如何处理请求时,发送404(Not Found)状态码给客户端。server.js部分代码修改如下:

} else {
    res.writeHead(404);
    res.end('Not Found');
}
1
2
3
4
这个时候,我们才真正完成了第一个HTTP Web服务器!!!
---------------------
作者:梦小白
来源:CSDN
原文:https://blog.csdn.net/qq_15096707/article/details/53706292
版权声明:本文为博主原创文章,转载请附上博文链接!

猜你喜欢

转载自blog.csdn.net/Golden_soft/article/details/83181081