node入门(三)HTTP
2015-11-24 16:39:57

168
资源大全
http://baike.baidu.com/view/9472.htm
http://www.zhihu.com/question/22689579
服务器
服务器可以是大型机也可以是个人电脑,只要能跑相应的程序就行 在特定服务器特定端口进行监听客户端的请求,根据请求的路径返回结果都叫服务器: 比如霍营庆丰包子店 国风美唐4号楼:1701 返回包子
客户端
各种软件,运行在个人mac、iphone、ipad、apple等等 向某个服务器的某个端口发起连接请求 比如向包子店发请求可以是打电话订餐,可以在门面喊,也可以通过百度外卖订餐 像这种通过发送请求获取服务器资源的都可称为客户端 服务器端和客户端的角色有些时候可能互换,但在一次通信过程中角色是固定的
数据
有时候不是传生成好的 HTML 或者其他服务器上已经有的文件,而是传输经过一定逻辑处理后生成的字符串或者其他各种封装好的数据
http协议
人与人之间通信,需要一种传输手段(声波/无线电)和一种彼此都懂的语言(比如普通话/广东话) 要让这些形形色色的机器能够通过网络进行交互,我们就需要指明一种协议(比如 HTTP/HTTPS)和一种数据封装格式(比如 HTML/XML), 服务器提供的服务就是指的就是这种协议+格式的交流体系。
一个普通网站访问的过程
- 浏览器(或其它客户端如微信)向服务器发出一个 HTTP请求
- 先解析域名(chrome缓存1分钟(chrome://net-internals/#dns)->搜索操作系统缓存->读取本地host文件->发起DNS系统调用->运营商DNS缓存->找根域->com域)
- 客户端通过随机端口发起tcp三次握手,经过层层服务器进入到网卡,然后进入防火墙和TCP协议栈,建立了TCP连接
- 连接建立后浏览器就可以发送HTTP请求了
- 服务器接收到 HTTP 请求,解析请求的路径和参数,经过后台的一些处理之后生成完整响应页面
- 服务器将生成的页面作为HTTP响应的body,根据不同的处理结果生成 HTTP header,发回给客户端
- 客户端(浏览器)接收到 HTTP 响应,通常第一个请求得到的 HTTP 响应的 body 里是 HTML 代码,于是对 HTML 代码开始解析
- 解析过程中遇到引用的服务器上的资源(额外的 CSS、JS代码,图片、音视频,附件等),再向服务器发送请求
- 浏览器解析HTML包含的内容,用得到的 CSS 代码进行外观上的进一步渲染,JS 代码也可能会对外观进行一定的处理
- 用户与页面交互(点击,悬停等等)时,JS 代码对此作出一定的反应,添加特效与动画
- 交互的过程中可能需要向服务器索取或提交额外的数据(局部的刷新),一般不是跳转就是通过 JS 代码(响应某个动作或者定时)向服务器发送请求, Web Server 再用服务器脚本进行处理(生成资源or写入数据之类的),把资源返回给客户端,客户端用得到的资源来实现动态效果或其他改变。
URL统一资源定位符
请求和响应
都会发送头和正文信息 http头发送的是一些附加的信息,内容类型服务器发送的响应的日期,HTTP状态码 正文是提交的表单数据
curl -v http://www.baidu.com
请求方法
以何种方式处理对应的资源
GET
请求访问已被URL识别的资源 获取对应的数据和资源
POST 传输实体主体
POST方法用来传输实体的主体 向指定的资源去提交数据
PUT
更新资源,向指定的资源上传内容
DELETE
删除指定的资源
HEAD
获取头信息
OPTIONS
获取支持的方法
状态码
1xx 请求已经接受正在处理 2xx 成功处理 3xx 重定向 4xx 客户端错误 5xx 服务器端错误 200 成功 400语法 错误 401拒绝服务 404没找到 500 服务器错误 503 暂不能处理
无状态
HTTP协议本身不具备保存之前发送过的请求或响应的功能 cookie
实战
- 返回一个字符串
- 返回一个index.html
- 增加css进行渲染
- 增加JS特效,局部刷新
参考资源
基本用法
处理GET请求
Http模块主要用于搭建HTTP服务。使用Node.js搭建HTTP服务器非常简单。
var http = require('http');
http.createServer(function (request, response){ response.writeHead(200, {'Content-Type': 'text/plain'}); response.end('Hello World\n'); }).listen(8080, "127.0.0.1");
console.log('Server running on port 8080.');
{% endhighlight %}
上面代码第一行var http = require("http"),表示加载http模块。然后,调用http模块的createServer方法,创造一个服务器实例,将它赋给变量http。
ceateServer方法接受一个函数作为参数,该函数的request参数是一个对象,表示客户端的HTTP请求;response参数也是一个对象,表示服务器端的HTTP回应。response.writeHead方法表示,服务器端回应一个HTTP头信息;response.end方法表示,服务器端回应的具体内容,以及回应完成后关闭本次对话。最后的listen(8080)表示启动服务器实例,监听本机的8080端口。
将上面这几行代码保存成文件app.js,然后用node调用这个文件,服务器就开始运行了。
{% highlight bash %}
$ node app.js
{% endhighlight %}
这时命令行窗口将显示一行提示“Server running at port 8080.”。打开浏览器,访问http://localhost:8080,网页显示“Hello world!”。
上面的例子是当场生成网页,也可以事前写好网页,存在文件中,然后利用fs模块读取网页文件,将其返回。
var http = require('http'); var fs = require('fs');
http.createServer(function (request, response){ fs.readFile('data.txt', function readData(err, data) { response.writeHead(200, {'Content-Type': 'text/plain'}); response.end(data); }); }).listen(8080, "127.0.0.1");
console.log('Server running on port 8080.');
下面的修改则是根据不同网址的请求,显示不同的内容,已经相当于做出一个网站的雏形了。
var http = require("http");
http.createServer(function(req, res) {
// 主页 if (req.url == "/") { res.writeHead(200, { "Content-Type": "text/html" }); res.end("Welcome to the homepage!"); } // About页面 else if (req.url == "/about") { res.writeHead(200, { "Content-Type": "text/html" }); res.end("Welcome to the about page!"); } // 404错误 else { res.writeHead(404, { "Content-Type": "text/plain" }); res.end("404 error! File not found."); }
}).listen(8080, "localhost");
回调函数的req(request)对象,拥有以下属性。
- url:发出请求的网址。
- method:HTTP请求的方法。
- headers:HTTP请求的所有HTTP头信息。
处理POST请求
当客户端采用POST方法发送数据时,服务器端可以对data和end两个事件,设立监听函数。
var http = require('http');
http.createServer(function (req, res) { var content = "";
req.on('data', function (chunk) { content += chunk; }); req.on('end', function () { res.writeHead(200, {"Content-Type": "text/plain"}); res.write("You've sent: " + content); res.end(); });
}).listen(8080);
data事件会在数据接收过程中,每收到一段数据就触发一次,接收到的数据被传入回调函数。end事件则是在所有数据接收完成后触发。
对上面代码稍加修改,就可以做出文件上传的功能。
javascript
"use strict";
var http = require('http'); var fs = require('fs'); var destinationFile, fileSize, uploadedBytes;
http.createServer(function (request, response) { response.writeHead(200); destinationFile = fs.createWriteStream("destination.md"); request.pipe(destinationFile); fileSize = request.headers['content-length']; uploadedBytes = 0;
request.on('data', function (d) { uploadedBytes += d.length; var p = (uploadedBytes / fileSize) * 100; response.write("Uploading " + parseInt(p, 0) + " %\n"); }); request.on('end', function () { response.end("File Upload Complete"); });
}).listen(3030, function () { console.log("server started"); });
发出请求
get()
get方法用于发出get请求。
javascript
function getTestPersonaLoginCredentials(callback) { return http.get({ host: 'personatestuser.org', path: '/email' }, function(response) { var body = '';
response.on('data', function(d) { body += d; }); response.on('end', function() { var parsed = JSON.parse(body); callback({ email: parsed.email, password: parsed.pass }); }); });
},
request()
request方法用于发出HTTP请求,它的使用格式如下。
javascript http.request(options[, callback])
request方法的options参数,可以是一个对象,也可以是一个字符串。如果是字符串,就表示这是一个URL,Node内部就会自动调用url.parse(),处理这个参数。
options对象可以设置如下属性。
- host:HTTP请求所发往的域名或者IP地址,默认是localhost。
- hostname:该属性会被url.parse()解析,优先级高于host。
- port:远程服务器的端口,默认是80。
- localAddress:本地网络接口。
- socketPath:Unix网络套接字,格式为host:port或者socketPath。
- method:指定HTTP请求的方法,格式为字符串,默认为GET。
- path:指定HTTP请求的路径,默认为根路径(/)。可以在这个属性里面,指定查询字符串,比如/index.html?page=12。如果这个属性里面包含非法字符(比如空格),就会抛出一个错误。
- headers:一个对象,包含了HTTP请求的头信息。
- auth:一个代表HTTP基本认证的字符串user:password。
- agent:控制缓存行为,如果HTTP请求使用了agent,则HTTP请求默认为Connection: keep-alive,它的可能值如下:
- undefined(默认):对当前host和port,使用全局Agent。
- Agent:一个对象,会传入agent属性。
- false:不缓存连接,默认HTTP请求为Connection: close。
- keepAlive:一个布尔值,表示是否保留socket供未来其他请求使用,默认等于false。
- keepAliveMsecs:一个整数,当使用KeepAlive的时候,设置多久发送一个TCP KeepAlive包,使得连接不要被关闭。默认等于1000,只有keepAlive设为true的时候,该设置才有意义。
request方法的callback参数是可选的,在response事件发生时触发,而且只触发一次。
http.request()返回一个http.ClientRequest类的实例。它是一个可写数据流,如果你想通过POST方法发送一个文件,可以将文件写入这个ClientRequest对象。
下面是发送POST请求的一个例子。
javascript var postData = querystring.stringify({ 'msg' : 'Hello World!' });
var options = { hostname: 'www.google.com', port: 80, path: '/upload', method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Content-Length': postData.length } };
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('BODY: ' + chunk); }); });
req.on('error', function(e) { console.log('problem with request: ' + e.message); });
// write data to request body req.write(postData); req.end();
注意,上面代码中,req.end()必须被调用,即使没有在请求体内写入任何数据,也必须调用。因为这表示已经完成HTTP请求。
发送过程的任何错误(DNS错误、TCP错误、HTTP解析错误),都会在request对象上触发error事件。
搭建HTTPs服务器
搭建HTTPs服务器需要有SSL证书。对于向公众提供服务的网站,SSL证书需要向证书颁发机构购买;对于自用的网站,可以自制。
自制SSL证书需要OpenSSL,具体命令如下。
openssl genrsa -out key.pem openssl req -new -key key.pem -out csr.pem openssl x509 -req -days 9999 -in csr.pem -signkey key.pem -out cert.pem rm csr.pem
上面的命令生成两个文件:ert.pem(证书文件)和 key.pem(私钥文件)。有了这两个文件,就可以运行HTTPs服务器了。
Node.js提供一个https模块,专门用于处理加密访问。
var https = require('https'); var fs = require('fs');
var options = { key: fs.readFileSync('key.pem'), cert: fs.readFileSync('cert.pem') };
var a = https.createServer(options, function (req, res) { res.writeHead(200); res.end("hello world\n"); }).listen(8000);
上面代码显示,HTTPs服务器与HTTP服务器的最大区别,就是createServer方法多了一个options参数。运行以后,就可以测试是否能够正常访问。
curl -k https://localhost:8000
模块属性
(1)HTTP请求的属性
- headers:HTTP请求的头信息。
- url:请求的路径。
模块方法
(1)http模块的方法
- createServer(callback):创造服务器实例。
(2)服务器实例的方法
- listen(port):启动服务器监听指定端口。
(3)HTTP回应的方法
- setHeader(key, value):指定HTTP头信息。
- write(str):指定HTTP回应的内容。
- end():发送HTTP回应。
创建一个http服务器
使用 Node.js 时,我们不仅仅 在实现一个应用,同时还实现了整个 HTTP 服务器。事实上,我们的 Web 应用以及对应的 Web 服务器基本上是一样的。 在我们创建 Node.js 第一个 "Hello, World!" 应用前,让我们先了解下 Node.js 应用是由哪几部分组成的:
- 引入 required 模块:我们可以使用 require 指令来载入 Node.js 模块。
- 创建服务器:服务器可以监听客户端的请求,类似于 Apache 、Nginx 等 HTTP 服务器。
- 接收请求与响应请求 服务器很容易创建,客户端可以使用浏览器或终端发送 HTTP 请求,服务器接收请求后返回响应数据。
创建 Node.js 应用
一、通过required方法引入模块
我们使用 require 指令来载入 http 模块,并将实例化的 HTTP 赋值给变量 http,实例如下:
var http = require("http");
二、创建服务器
接下来我们使用 http.createServer() 方法创建服务器,并使用 listen 方法绑定 8080 端口。 函数通过 request, response 参数来接收和响应数据。 实例如下,在你项目的根目录下创建一个叫 app.js 的文件,并写入以下代码:
var http = require('http');//请求(require)Node.js 自带的 http 模块,并且把它赋值给 http 变量。 /** * 调用 http 模块提供的函数: createServer 。 * 这个函数会返回一个对象,这个对象有一个叫做 listen 的方法,这个方法有一个数值参数, 指定这个 HTTP 服务器监听的端口号。 **/ http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); //写入头信息 指定内容类型=text/plain res.end('Hello World\n'); //发送响应体数据 }).listen(1337, "127.0.0.1"); //监听本机的1337端口 //在控制台上打印如下信息 console.log('Server running at http://127.0.0.1:1337/');
通过以上代码我们完成了高性能的HTTP服务器。
使用 node 命令执行以上的代码:
node app.js Server running at http://127.0.0.1:8080/
接下来,打开浏览器访问 http://127.0.0.1:8080/,你会看到一个写着 "Hello World"的网页。