一、使用Node实现基本Apache的功能

在上一篇笔记中,我们提到如果打开一个文件需要进行一次url判断是繁琐的,我们希望我们的Node具有类似Apache这种web服务器的一个功能:将文件放到www这个文件夹下,我们只要输入对应的文件地址就能访问到相应文件。

之前我们是对每一个文件进行request.url判断,再处理相应的Content-Type,这样比较麻烦,现在我们对url进行统一处理即可:

  • 要模拟www文件的功能,我们先将我们的项目放到www文件夹下:

  • 统一处理访问www文件夹下文件的url
var http = require('http');
var fs = require('fs'); var server = http.createServer();
server.listen(8000);
console.log('server running'); server.on('request',function(request,response){
var url = request.url;
var rootDir = 'D:/Users/Administrator/Desktop/Node/www';//www文件夹路径
var filePath = '/index.html';//文件地址,默认打开index.html
if(url !== '/'){
filePath = url;
} //根据url打开文件
fs.readFile(rootDir+filePath,function(err,data){
if(err){
return response.end('404,Not Fond!');
}
response.end(data);
});
});

原理是一样的,只不过进行了统一处理;浏览器其实会自动判断data的类型来处理文件,所以很多时候不用设置Content-Type。

二、案例:使用Node实现显示文件目录的效果

在浏览器中输入目录地址我们可以看到这样的效果:

现在使用Node来实现这个效果,我们需要知道fs模块的一个方法:readdir()即读取目录:

var http = require('http');
var fs = require('fs'); var server = http.createServer();
server.listen(8000);
console.log('server running'); server.on('request',function(request,response){
var url = request.url;
var rootDir = 'D:/Users/Administrator/Desktop/Node/www';//www文件夹路径 //读取目录
fs.readdir(rootDir,function(err,data){
if(err){
return response.end('404,Not Fond!');
}
console.log(data);
});
});

可以发现,读取的数据data是以数组形式显示出对于路径下的文件(夹)名。

现在我们只需要将这些数据显示在页面中即可,怎么将数据变成网页效果呢,一般情况下我们可以使用模块代码来提高效率,类似这样的逻辑:

其实就是想数据填到对应的位置,而不用去关心相应的页面效果,页面效果交给模板代码来处理,我们只需要关注两件事:获取数据data;将data填入模板代码中并使用。

(这里的模板代码我们自己随便写一个好了)

1.编写模板代码


<!DOCTYPE html>
<html>
<head>
<title>DirShow</title>
</head>
<body>
<h1>XXXURL的索引</h1>
<div style="display: block;">
<a href="#">
<span>[上级目录]</span>
</a>
</div>
<table>
<thead>
<tr>
<th>名称</th>
<th class="detailsColumn">
大小
</th>
<th class="detailsColumn">
修改日期
</th>
</tr>
</thead>
<tbody id="tbody">
<tr>
<td><a href="#">css/</a></td>
<td>1k</td>
<td>2018/11/5 上午10:50:48</td>
</tr>
</tbody>
</table>
</body>
</html>

效果如上,我们把框起来的部分使用我们读取的data替换掉就好了:

2.获取数据

上面已经获取过,使用readdir()方法来获取:

3.将数据填充到模板中并使用

我们发现模板代码其实就是字符串而已,我们将数据填充进去,其实就是进行简单的字符串替换工作即可:

var http = require('http');
var fs = require('fs'); var server = http.createServer();
server.listen(8000);
console.log('server running'); server.on('request',function(request,response){
var url = request.url;
var rootDir = 'D:/Users/Administrator/Desktop/Node/www'+url;//根据请求路径显示 //创建模板代码
var contentTemplate = `
<tr>
<td><a href="#">filename</a></td>
<td>1k</td>
<td>2018/11/5 上午10:50:48</td>
</tr>
`;
var content = '';
//获取数据
fs.readdir(rootDir,function(err,data){
if(err){
return response.end('404,Not Fond!');
}
//将数据填充到模板代码中---字符串替换操作
data.forEach(function(value,index){
content += contentTemplate.replace('filename',value);
//更新和使用模板代码
});
var templateStr = `
<h1>${rootDir}的索引</h1>
<div style="display: block;">
<a href="#">
<span>[上级目录]</span>
</a>
</div>
<table>
<thead>
<tr>
<th>名称</th>
<th class="detailsColumn">
大小
</th>
<th class="detailsColumn">
修改日期
</th>
</tr>
</thead>
<tbody id="tbody">
${content}
</tbody>
</table>
`;
response.setHeader('Content-Type','text/html;charset=utf-8');
response.end(templateStr);
});
});

效果如下:

三、模板引擎

模板引擎是什么这里就不过多介绍了,从上面的案例中我们已近手动实现了模板引擎要做的事,处理字符串,更准确地说应该是将数据填充到模板代码这一字符串操作过程我们可以通过模板引擎来完成。

模板引擎有诸多优点,这里不再赘述,我们在使用中感受。比如art-yemplate模板引擎。官网地址:art-yemplate

1.安装art-template

既然使用了Node.js我们就尽量使用npm来安装,新建一个文件夹code来保存代码:

2.在浏览器中使用art-template

<!DOCTYPE html>
<html>
<head>
<title>Demo</title>
<mata charset=utf-8>
<script type="text/javascript" src="./code/node_modules/art-template/lib/template-web.js"></script>
</head>
<body>
<!--显示位置-->
<p id="show"></p> <!--模板代码-->
<script type="text/html" id='demo'>
大家好,我叫{{ name }},
我喜欢{{each hobbies}}{{$value}} {{/each}}
</script> <script type="text/javascript">
//数据
var data = {
name: '张三',
hobbies: ['看书','打游戏','写代码']
};
//使用template方法将数据填充到模板中
var html = template('demo',data);
//将模板显示到页面上
window.document.getElementById('show').innerHTML = html;
</script>
</body>
</html>

注意几点:

  • 记得引用template-web.js文件
  • 相关格式要求和api查看官网文档即可
  • 模板引擎不关心格式以及内容,只是将{{}}表达式中的值进行数据填充,和我们手动replace处理字符串的操作是一样的。
  • 模板引擎还有其他好处,比如根据语句来处理数据,内部引用等。比我们手动处理字符串要方便很多,算是一个介绍代码工作的工具,且运行速度很快,渲染接近原生js。(有的模板引擎稍慢)

3.在Node.js中使用art-template

我们直接在上面的案例上进行改动即可:

var http = require('http');
var fs = require('fs');
var template = require('art-template');//启用art-template模板引擎 var server = http.createServer();
server.listen(8000);
console.log('server running'); server.on('request',function(request,response){
var url = request.url;
var rootDir = 'D:/Users/Administrator/Desktop/Node/www'+url;//根据请求路径显示 //创建模板代码
var templateStr = `
<h1>{{dir}}的索引</h1>
<div style="display: block;">
<a href="#">
<span>[上级目录]</span>
</a>
</div>
<table>
<thead>
<tr>
<th>名称</th>
<th class="detailsColumn">
大小
</th>
<th class="detailsColumn">
修改日期
</th>
</tr>
</thead>
<tbody id="tbody">
{{each data}}
<tr>
<td><a href="#">{{$value}}</a></td>
<td>1k</td>
<td>2018/11/5 上午10:50:48</td>
</tr>
{{/each}}
</tbody>
</table>
`;
//获取数据
fs.readdir(rootDir,function(err,data){
if(err){
return response.end('404,Not Fond!');
}
//使用模板引擎填充数据
var htmStr = template.render(templateStr,{
dir:rootDir,
data:data
});
response.setHeader('Content-Type','text/html;charset=utf-8');
response.end(htmStr);
});
});

值得注意的点:

  • 在Node.js中使用require()来加载模板引擎
  • 使用模板引擎的render()方法来处理模板代码(在浏览器在中是template()方法)
  • 在浏览器中是使用id作为参数,在Node.js中直接使用模板代码作为参数即可。
  • 注意模板代码要符合使用的模板引擎的规范。${value}是es6中模板字符串的变量表达式,而{{}}是art-template模板引擎的表达式。

四、案例:留言板

需求:使用Node.js实现留言板功能,即在如下页面输入评论,首页显示评论,相关html和css代码如下:

1.准备工作

目录结构如下:

html代码(views文件夹下)

js/css/img(public文件夹下,其实只用到了bootstrap.css,可自行网上下载引用)

模板引擎代码(node_modules文件夹下)

index.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>留言本</title>
<link rel="stylesheet" href="../public/css/bootstrap.css">
</head>
<body>
<div class="header container">
<div class="page-header">
<h1>Example page header <small>Subtext for header</small></h1>
<a class="btn btn-success" href="/post">发表留言</a>
</div>
</div>
<div class="comments container">
<ul class="list-group">
{{each comments}}
<li class="list-group-item">
<span style="color: green">{{ $value.name }}:</span>{{ $value.message }}
<span class="pull-right">{{ $value.dateTime }}</span>
</li>
{{/each}}
</ul>
</div>
</body>
</html>

post.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" href="../public/css/bootstrap.css">
</head>
<body>
<div class="header container">
<div class="page-header">
<h1><a href="/">首页</a> <small>发表评论</small></h1>
</div>
</div>
<div class="comments container">
<form action="/addComment" method="post">
<div class="form-group">
<label for="input_name">你的大名</label>
<input type="text" class="form-control" required minlength="2" maxlength="10" id="input_name" name="name" placeholder="请写入你的姓名">
</div>
<div class="form-group">
<label for="textarea_message">留言内容</label>
<textarea class="form-control" name="message" id="textarea_message" cols="30" rows="10" required minlength="1" maxlength="20"></textarea>
</div>
<button type="submit" class="btn btn-default">发表</button>
</form>
</div>
</body>
</html>

404.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<h1>抱歉! 您访问的页面失联啦...</h1>
</body>
</html>

2.编写app.js文件(post提交)

var http = require('http');
var fs = require('fs');
var template = require('art-template'); var comments = []; http.createServer(function(req,res){
var url = req.url;
var rootDir = 'D:/Users/Administrator/Desktop/Node/feadback';
var filePath = '/views/index.html';
if(url === '/addComment'){
//request的data事件
req.on('data',function(postdata){
//postdata是二进制数据,postdata.toString()返回的数据编码方式任然有问题,所以需要解码
var decodedata = decodeURIComponent(postdata.toString());//对表单数据进行解码--->name=xxx&massage=xxx
var data = {},key,value,arr;
decodedata.split('&').forEach(function(v){
arr = v.split('=');
key = arr[0];
value = arr[1] || '';
data[key] = value;
});
data['dateTime'] = new Date().toLocaleString();
comments.unshift(data);
});
url = '/';
}
if(url !== '/'){
filePath = url;
}
if(url === '/post'){
filePath = '/views/post.html';
}
if(url !== '/'){
fs.readFile(rootDir+filePath,function(err,data){
if(err){
fs.readFile(rootDir+'/views/404.html',function(err1,data1){
if(err1)
return res.end('404,Not Fond.');
return res.end(data1);
})
return;
}
res.end(data);
});
}else{
//index.html需要进行模板渲染
fs.readFile(rootDir+filePath,function(err,data){
if(err){
fs.readFile(rootDir+'/views/404.html',function(err1,data1){
if(err1)
return res.end('404,Not Fond.');
return res.end(data1);
})
return;
}
var html = template.render(data.toString(),{comments:comments});
res.end(html);
});
}
}).listen(8000);
console.log('server running...');

值得注意的一些细节:

  • 注意fileRead()读取到的数据是二进制数据,要当做模板代码需要使用toString()进行处理。
  • 我们使用的是post提交,那么表单数据就不会显示在url上,我们需要使用request的data事件来获取post提交获得的数据。
  • postdata也是二进制数据,且使用toString()方法后编码任然可能不是正常编码,需要使用decodeURIComponent()方法进行解码。
  • 将表单提交的数据添加到数组中,使用模板引擎渲染到页面即可。

3.get提交的一些区别

首先,request.url会变成这样:

也就是多了后面的参数,那么if(url === '/addComment')就会失效,而request的data事件也不会触发。

所以如果是get提交,我们需要使用另外的处理方式。

  • 首先使用url核心模板即:var url = require('url');
  • 使用url核心模板的parse()方法来处理request.url。
//将路径解析为一个方便操作的对象,
//第二个参数为 true 表示直接将查询字符串转为一个对象(通过 query 属性来访问)
var parseObj = url.parse(req.url, true);
  • true这个参数很重要,否则parseObj.query会转化为字符串。
  • 此时parseObj对象就包含了url的相关信息,如parseObj.pathname表示当前请求连接(不带hash参数,本例中即为'/addComment')。而parseObj.query可以获取hash参数转化而成的对象,本例即:{name:xxx,messagexxx},且不用再使用decodeURIComponent()进行解码也不会乱码。

Node.js(day2)的更多相关文章

  1. node.js学习(三)简单的node程序&&模块简单使用&&commonJS规范&&深入理解模块原理

    一.一个简单的node程序 1.新建一个txt文件 2.修改后缀 修改之后会弹出这个,点击"是" 3.运行test.js 源文件 使用node.js运行之后的. 如果该路径下没有该 ...

  2. 利用Node.js的Net模块实现一个命令行多人聊天室

    1.net模块基本API 要使用Node.js的net模块实现一个命令行聊天室,就必须先了解NET模块的API使用.NET模块API分为两大类:Server和Socket类.工厂方法. Server类 ...

  3. Node.js:进程、子进程与cluster多核处理模块

    1.process对象 process对象就是处理与进程相关信息的全局对象,不需要require引用,且是EventEmitter的实例. 获取进程信息 process对象提供了很多的API来获取当前 ...

  4. Node.js:理解stream

    Stream在node.js中是一个抽象的接口,基于EventEmitter,也是一种Buffer的高级封装,用来处理流数据.流模块便是提供各种API让我们可以很简单的使用Stream. 流分为四种类 ...

  5. Node.js:Buffer浅谈

    Javascript在客户端对于unicode编码的数据操作支持非常友好,但是对二进制数据的处理就不尽人意.Node.js为了能够处理二进制数据或非unicode编码的数据,便设计了Buffer类,该 ...

  6. node.js学习(二)--Node.js控制台(REPL)&&Node.js的基础和语法

    1.1.2 Node.js控制台(REPL) Node.js也有自己的虚拟的运行环境:REPL. 我们可以使用它来执行任何的Node.js或者javascript代码.还可以引入模块和使用文件系统. ...

  7. Node.js npm 详解

    一.npm简介 安装npm请阅读我之前的文章Hello Node中npm安装那一部分,不过只介绍了linux平台,如果是其它平台,有前辈写了更加详细的介绍. npm的全称:Node Package M ...

  8. Node.js入门(一)

    一.Node.js本质上是js的运行环境. 二.可以解析js代码(没有浏览器安全级的限制): 提供系统级的API:1.文件的读写 2.进程的管理 3.网络通信 三.可以关注的四个网站: 1.https ...

  9. Node.js学习笔记——Node.js开发Web后台服务

    一.简介 Node.js 是一个基于Google Chrome V8 引擎的 JavaScript 运行环境.Node.js 使用了一个事件驱动.非阻塞式 I/O 的模型,使其轻量又高效.Node.j ...

随机推荐

  1. Python的安装图解

    安装步骤: 第一步:打开Python官网:http://www.python.org 第二步:点击Download,下载windows版本 第三步:选择要下载的版本第四步:安装到指定的位置第五步:验证 ...

  2. Contours 等高线图

    1.画等高线 数据集即三维点 (x,y) 和对应的高度值,共有256个点.高度值使用一个 height function f(x,y) 生成. x, y 分别是在区间 [-3,3] 中均匀分布的256 ...

  3. 浅谈Java和PHP的异同

    编程范式: Java:纯面向对象的语言,有人说过:Java中一切皆对象!当然咯,人们都忘了Java的八种基本数据类型:int.double.boolean.byte.float.long.short. ...

  4. vb编程中的is是什么意思??

    在select case 语句中可以使用关系运算符大于>小于<等于=等关系运算符,需要用关键字IS和TO.用个例子来说明:Private Sub Command1_Click()Dim a ...

  5. matplotlib 中文显示问题

    matplotlib 默认显示不了中文,如果想显示中文,通过下面代码设置: import matplotlib #指定默认字体 matplotlib.rcParams['font.sans-serif ...

  6. ibatis中的resultMap

    优点: resultMap可以实现一种功能 当你是1对多 这种多张表查询的时候 你没办法 通过表连接来实现一个集合设置到一个实例里,但是通过resultMap里可以做到 根据关联的字段 查询到一个集合 ...

  7. 口试Linq题

    LINQ to SQL与IQueryable 理解IQueryable的最简单方式就是,把它看作一个查询,在执行的时候,将会生成结果序列. LINQ to Object和LINQ to SQL有何区别 ...

  8. Python中利用进度条求圆周率

    从祖冲之到现在,圆周率的发展越来越丰富,求法也是越来越快其中: 1.求圆周率的方法: (1)蒙特卡罗法 这是基于“随机数”的算法,通过计算落在单位圆内的点与正方形内的比值来求圆周率PI. 如果一共投入 ...

  9. zepto 源码 $.contains 学习笔记

    $.contains(parent,node)  返回值为一个布尔值 ==> boolean parent,node我们需要检查的节点检查父节点是否包含给定的dom节点,如果两者是相同的节点,返 ...

  10. Mybatis第二天

    Mybatis第二天   框架课程 1. 课程计划 1.输入映射和输出映射 a) 输入参数映射 b) 返回值映射 2.动态sql a) If标签 b) Where标签 c) Sql片段 d) Fore ...