使用nodejs实现静态服务器与用到的方法

添加node内置模块,通过require加载:

var http = require('http')
var path = require('path')
var fs = require('fs')
var url = require('url')

整个底层服务器是由node提供的http模块实现的。

创建server

http.server是一个基于事件的HTTP服务器,所有的请求都被封装到独立的事件当中。

http.createServer(function(req, res){
    res.setHeader('Content-Type','text/html; charset=utf-8')
    res.writeHead(200, 'ok')
    res.write('hello world')
    res.end()
})

两个参数request和response,分别是http.ServerRequest和http.ServerResponse表示请求和响应的信息。

http.ServerResponse返回客户端信息

决定了用户最终能到的结果,它是由http.Server的request事件发送的,作为第二个参数传递,一般用response或res表示。
主要的三个函数:

  • response.writeHead(statusCode, [headers]):向请求的客户端发送响应头。statusCode是HTTP的状态码,如200为成功,404未找到等。headers是一个类似关联数组的对象,表示响应头的每个属性。
  • response.write(data, [encoding]):向请求客户端发送相应内容,data是buffer或字符串,encoding为编码。
  • response.end([data], [encoding]):结束响应,告知用户所有发送已经完成,当所有要返回的内容发送完毕,该函数必须被调用一次,如果不调用,客户端永远处于等待状态

http.ServerRequset请求信息

HTTP请求分为两部分请求头请求体,如果请求内容少直接在请求头协议完成之后立即读取,请求体相对较长,需要一定的时间传输,因此提供了三个事件用于控制请求体传输:
data:当请求体数据到来时,该事件被触发,有一个参数chunk,表示接受到的数据。
end:当请求体数据传输完成时,该事件被触发,此后将不会再有数据到来。
close:用户当前请求结束时,该事件被触发,不同于end,如果用户强制终止了传输,也会触发close。
ServerRequset的属性:

名称 含义
complete 客户端请求是否已经发送完成
httpVersion HTTP协议版本,通常是1.0或1.1
method HTTP请求方法,如GET、POST
url 原始的请求路径
headers HTTP请求头
trailers HTTP请求尾(不常见)
connection 当前HTTP连接套接字,为net.Socket的实例
socket connection属性的别名
client client属性的别名

获取GET请求内容

由于GET请求直接被嵌入在路径中,URL是完整的请求路径,包括了?后面的部分,因此可以手动解析后面的内容作为GET请求的参数。
node.js中url模块中的parse函数提供了这个功能。
参考:Node.js GET/POST请求

var http = require('http');
var url = require('url');
var util = require('util');
 
http.createServer(function(req, res){
    res.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});
    //利用url模块去解析客户端发送过来的Url对象
    res.end(util.inspect(url.parse(req.url, true)));
}).listen(8080);

注:util.inspect
util.inspect(object, [showHidden], [depth], [colors])是一个将任意对象转换为字符串的方法,通常用于调试和错误输出。它至少接受一个参数object,即要转换的对象。
showHidden:是一个可选参数,如果值为true,将会输出更多隐藏信息。
depth:表示最大递归的层数,如果对象很复杂,可以指定层数以控制输出信息的多少。如果不指定depth,默认会递归2层,指定为null表示将不限递归层数完整遍历对象。
color:如果值为true,输出格式将会以ANSI颜色编码,通常用于在终端显示更漂亮的效果。
特别要指出的是,util.inspect并不会简单地直接把对象转换为字符串,即使该对象定义了toString方法也不会调用。
参考:Node.js常用工具

var util = require('util'); 
function Person() { 
    this.name = 'byvoid'; 
    this.toString = function() { 
    return this.name; 
    }; 
} 
var obj = new Person(); 
console.log(util.inspect(obj)); 
console.log(util.inspect(obj, true));

输出结果:

Person { name: 'byvoid', toString: [Function] }
Person {
  name: 'byvoid',
  toString: 
   { [Function]
     [length]: 0,
     [name]: '',
     [arguments]: null,
     [caller]: null,
     [prototype]: { [constructor]: [Circular] } } }

获取POST请求内容

POST 请求的内容全部的都在请求体中,http.ServerRequest 并没有一个属性内容为请求体,原因是等待请求体传输可能是一件耗时的工作。
比如上传文件,而很多时候可能并不需要理会请求体的内容,恶意的POST请求会大大消耗服务器的资源,所以node.js默认是不会解析请求体的,当需要时要手动来做。
参考:Node.js GET/POST请求
基本语法结构:

var http = require('http');
var querystring = require('querystring');
http.createServer(function(req, res){
    // 定义了一个post变量,用于暂存请求体的信息
    var post = '';     
    // 通过req的data事件监听函数,每当接受到请求体的数据,就累加到post变量中
    req.on('data', function(chunk){    
        post += chunk;
    });
    // 在end事件触发后,通过querystring.parse将post解析为真正的POST请求格式,然后向客户端返回。
    req.on('end', function(){    
        post = querystring.parse(post);
        res.end(util.inspect(post));
    });
}).listen(8080);

举例:表单通过 POST 提交并输出数据

var http = require('http');
var querystring = require('querystring');
 
var postHTML = 
  '<html><head><meta charset="utf-8"><title>菜鸟教程 Node.js 实例</title></head>' +
  '<body>' +
  '<form method="post">' +
  '网站名: <input name="name"><br>' +
  '网站 URL: <input name="url"><br>' +
  '<input type="submit">' +
  '</form>' +
  '</body></html>';
 
http.createServer(function (req, res) {
  var body = "";
  req.on('data', function (chunk) {
    body += chunk;
  });
  req.on('end', function () {
    // 解析参数
    body = querystring.parse(body);
    // 设置响应头部信息及编码
    res.writeHead(200, {'Content-Type': 'text/html; charset=utf8'});
 
    if(body.name && body.url) { // 输出提交的数据
        res.write("网站名:" + body.name);
        res.write("<br>");
        res.write("网站 URL:" + body.url);
    } else {  // 输出表单
        res.write(postHTML);
    }
    res.end();
  });
}).listen(3000);

访问‘localhost:3000’,在input表单中分别输入‘饥人谷’ ‘jirengu.com’,点提交,输出:

网站名:饥人谷
网站 URL:jirengu.com

__dirname和__filename

__dirname等同于path.dirname(__filename)
__dirname返回当前模块文件解析过后所在的文件夹(目录)的绝对路径;
__filename返回当前模块文件被解析过后的绝对路径。


举例,在index.js中:

console.log('这是staticPath:'+ staticPath)
console.log('这是req.url:'+ req.url)
console.log('这是__dirname:' + __dirname)
console.log('这是__filename:' + __filename)
console.log('这是path.dirname(__filename):' + path.dirname(__filename))
//输出
这是staticPath:/Users/WRX/projects/Demo/node-server/sample
这是req.url:/getWeather?city=beijing
这是__dirname:/Users/WRX/projects/Demo/node-server
这是__filename:/Users/WRX/projects/Demo/node-server/index.js
这是path.dirname(__filename):/Users/WRX/projects/Demo/node-server

fs.readFileSync方法

fs.readFileSync(filename, [encoding])
由于该方法属于fs模块,使用前需要引入fs模块(var fs = require('fs'))
接受参数:
filename:文件路径
options:option对象,包含encoding,编码格式,该项是可选的。
举例:

var fs = require('fs')
var contentText = fs.readFileSync('123.txt','utf-8')
console.log(contentText);

在index-simple.js中,文件路径filename为:__dirname + '/sample' + req.url,拼装成完整的路径。

try与catch的使用

try{
    //代码区
}catch(Exception e){
    //异常处理
}

代码区如果有错误,就会返回所写异常的处理。(如果没有try,出现异常会导致程序崩溃,而try则可以保证程序的正常运行。)
try catch是捕捉try部分的异常,当没有try时,如果出现异常程序报错,加上try catch,出现异常程序正常运行,只是把错误信息存储到Exception里,所以catch是用来提取异常信息的,可以在catch部分加System.out.println(e.ToString());,如果出现异常可以把异常打印出来。

println和print基本没什么差别,就是最后会换行。
print将它的参数显示在命令窗口,并将输出光标定位在所显示的最后一个字符之后。
println将它的参数显示在命令窗口,并在结尾加上换行符,将输出光标定位在下一行的开始。

url.parse(req.url,true)

将一个url字符串转换成对象并返回,使用前需要引入url(var url = require('url'))
url.parse(urlStr, [parseQueryString], [slashesDenoteHost]),默认情况url.parse(url)等价于url.parse(url, false, false)
接受参数:
urlStr:url字符串;
parseQueryString:控制解析的 Url {……} 中的query字段的值是否为JSON格式,即{……},还是普通字符串格式,即‘……’,默认false为字符串格式;
slashesDenoteHost:默认为false,//foo/bar形式的字符串将被解释成{pathname: ‘//foo/bar’};如果为true,//foo/bar形式的字符串将被解释成{host: ‘foo',pathname: ‘/bar'}。
举例:

var url = require('url');
var a = url.parse('http://localhost:8080/one?a=index&t=article');
console.log(a);
Url { 
    protocol : 'http' ,
    auth : null ,
    host : 'localhost:8080' ,
    port : '8080' ,
    hostname : 'localhost' ,
    hash : null ,
    search : '?a=index&t=article',
    query : 'a=index&t=article',
    pathname : '/one',
    path : '/one?a=index&t=article',
    href : 'http://localhost:8080/one?a=index&t=article'
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,820评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,648评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,324评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,714评论 1 297
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,724评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,328评论 1 310
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,897评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,804评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,345评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,431评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,561评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,238评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,928评论 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,417评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,528评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,983评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,573评论 2 359

推荐阅读更多精彩内容

  • 概要 64学时 3.5学分 章节安排 电子商务网站概况 HTML5+CSS3 JavaScript Node 电子...
    阿啊阿吖丁阅读 9,223评论 0 3
  • https://nodejs.org/api/documentation.html 工具模块 Assert 测试 ...
    KeKeMars阅读 6,340评论 0 6
  • 个人入门学习用笔记、不过多作为参考依据。如有错误欢迎斧正 目录 简书好像不支持锚点、复制搜索(反正也是写给我自己看...
    kirito_song阅读 2,479评论 1 37
  • 一、核心模块和对象 核心模块的意义 常用内置模块path:处理文件路径fs:操作文件系统child_process...
    EndEvent阅读 4,422评论 0 1
  • 最近在考研复习中,很多与考研无关的书、知识类的APP、公众号都不看了。考研,一种不知胜败,心里没底的感觉。三年...
    小小猫妖阅读 340评论 4 2