Node.js
介绍
Node.js是什么?
- Node.js不是一门语言。
- Node.js不是库,不是框架。
- Node.js是一个JavaScript运行时环境,即Node.js可以解析和执行JavaScript代码。
附:绝大多数JavaScript相关的包都存放在了npm上。
Node.js中的JavaScript
- 没有BOM,DOM。
- EcmaScript。
- 为JavaScript提供了一些服务器级别的API。
- event-driven 事件驱动
- non-blocking I/O model 非阻塞IO模型(异步)
Node.js能做什么?
- web服务器后台。
- 命令行工具
- webpack
- gulp
- npm
安装nodejs
选择合适自己电脑的版本下载,傻瓜式安装包安装,安装过程略。
检测是否安装成功
打开cmd,输入 node –v
查看版本。
若出现以下现象代表安装成功,版本号可能有所不同。
扩展
安装了nodejs后,不单止可以用编译器运行js代码,也可以用命令行运行编译。
- 进入js的目录下
- 执行
node 文件名.js
命令
注意:不要以node.js命名。
起步
npm使用介绍
安装node默认就安装了npm。
npm --version 查看npm版本
-
生成package.json文件:
npm init
npm init -y
可以跳过向导,快速生成
-
安装:
npm install [--save] <Module Name> [- g]
- 如果指定 -g 则是全局安装。
- –save保存依赖包信息到package.json文件中。
-
查看所有全局安装的模块:
npm list -g
-
查看某个模块:
npm list <Module Name>
-
卸载模块:
npm uninstall [--save] <Module Name>
-
更新模块:
npm update <Module Name>
-
搜索模块:
npm search <Module Name>
-
查看命令:
npm help [<command>]
-
清空NPM本地缓存:
npm cache clear
解决npm被墙问题
npm存储包文件的服务器在国外,有时候会很慢,因而安装淘宝的cnpm(http://npm.taobao.org/):
npm insatll --global cnpm
接着就把npm的命令中npm
替换成cnpm
即可。
- 如果不想安装
cnpm
又想使用淘宝的服务器来下载:
npm install 包名 --registry=https://registry.npm.taobao.org
但每一次手动加参数会很麻烦,但可以加上此配置:
npm config set registry https://registry.npm.taobao.org
# 查看 npm 配置信息
npm config list
ip地址和端口号(了解)
- IP地址用来定位计算机
- 端口号用来定位具体的应用程序,范围从0~65536之间。(所有需要联网通信的软件必须具有端口号)
模块版本号(x.y.z)
- 如果只修复bug,则更新z位。
- 增加功能,但向下兼容,更新y位。
- 有大变动,但向下不兼容,更新x位。
核心模块
- 文件操作:
fs
- http服务构建:
http
- 路径操作:
path
- 操作系统信息:
os
Node 中的其他成员(fs文件操作注意)
在每个模块中,除了 require
、exports
等模块相关API之外,还有两个特殊的成员:
__dirname
可以用来获取当前文件模块所属目录的绝对路径。__filename
可以用来获取当前文件的绝对路径。__dirname
和__filename
是不受执行node命令所属目录影响的。
在文件操作中,使用相对路径是不可靠的,因为在Node中文件操作的路径被设计为相对于执行node命令所处的路径。
为了解决问题,只需把相对路径变为绝对路径,利用__dirname
、__filename
。
文件模块(自定义模块)(重要)
文件模块是用户自己编写的模块,**通过require加载,且通过相对路径加载时必须加./
**
在Node中没有全局作用域,只有模块作用域,即模块间不能相互访问到内部,也不能访问到外部。
每个文件模块中都提供了一个导出对象:exports。
exports默认是一个空对象。
推荐加载时,.js
后缀省略。
模块系统(模块化)(重要)
模块规范
- 模块作用域
- 使用require方法加载模块
- 使用exports接口对象用来导出模块中的成员。
加载模块require
通过 **require
**指令用来载入使用Node.js模块。
作用:
- 加载核心模块(或文件模块)并执行里面的代码。
- 拿到被加载文件模块导出的接口对象exports。
var fs = require('fs');
导出 exports
-
导出多个成员
exports.a = 123;
-
导出一个成员
module.exports = 'hello';
以下情况会覆盖:
module.exports = 'hello'; // 后者覆盖前者 module.exports = function (x, y) { return x + y; }
也可以这样导出多个成员:
module.exports = { add: function (x, y) { return x + y; }, str: 'hello'; }
原理解析
exports 和 module.exports
的一个引用。
console.log(exports === module.exports);
每一个模板都会隐藏着这一块代码。(必须理解,导出一个和多个为什么不同,引用类型赋值的问题)
var module = {
exports: {}
}
exports = module.exports;
return module.exports;
例:
// a.js
console.log('a start');
require('./b.js');
console.log('a end');
/*
* 输出
* a start
* b start
* a end
* */
// b.js
console.log('b start');
因为模块间不能相互访问其内部,但可以通过 exports
导出。(核心模板原理也是这样)
// a.js
var b = require('./b');
console.log(b.foo);
console.log(b.add(10, 20));
/*
* 输出
* bbb
* 30
* */
// b.js
var foo = 'bbb';
exports.foo = foo;
exports.add = function(x, y) {
return x + y;
}
require加载规则
-
优先从缓存加载
// a.js require('./b.js'); require('./c.js'); // b.js console.log('b加载了'); require('./c.js'); // c.js console.log('c加载了'); // 输出(注意a.js最后一个会优先从缓存加载,不会再把代码重复执行,只会加载模块了) // b加载了 // c加载了
-
判断模块标识
-
核心模块,官方的。
-
第三方模块,加载语法与核心模块一样,但形式会不同,加载会首先搜索当前文件目录下的node_modules,然后搜索加载模块的名字,再找到模块目录下的package.json,找再到package.json中的main属性(记录了入口模块)。如果package.json或main属性不存在,默认加载模块目录下的index.js。
-
自定义模块,一般采取相对路径加载。
-
注意:项目中有且只能有一个node_modeules。
package.json(重要)
建议每一个项目根目录都要有一个 **package.json
**(就如产品的说明书)。
这个文件可以通过 npm init
的方式来自动初始化出来。
建议执行 npm install 包名
的时候都加上 --save
这个选项,目的是用来保存依赖项信息。
如果node_modules删除了,只需要 npm install
就会自动把package.json中的dependencies
中所有的依赖项都下载回来。
package.json 和 package-lock.json
npm 5以前是不会有 package-lock.json
这个文件。以后版本才加入的。
当你安装包的时候,npm都会生成或者更新 package-lock.json
这个文件。
- npm 5 以后的版本安装包不需要加
--save
参数,它会自动保存依懒信息。 - 当安装包的时候,会自动创建或者是更新
package-lock.json
这个文件。 package-lock.json
这个文件会保存node_modules
中所有包的信息(版本、下载地址)。package-lock.json
这个文件另一个作用就是锁定版本号,防止自动升级。
回调地狱
一个回调函数放在另一个回调函数内,保证执行顺序。
解决它带来的问题,所以EcmaScript 6新增了一个API叫promise。
promise(重要,ES6)
var fs = require('fs');
// 1.创建promise容器
var p1 = new Promise(function (resolve, reject) {
fs.readFile('a.txt', 'utf8', function (err, data) {
// 任务失败
if (err) {
// 把容器的pending状态改为Rejected
// 相当于调用then第二个参数
reject(err);
} else {
// 任务成功
resolve(data);
}
})
});
var p2 = new Promise(function (resolve, reject) {
fs.readFile('b.txt', 'utf8', function (err, data) {
// 任务失败
if (err) {
// 把容器的pending状态改为Rejected
// 相当于调用then第二个参数
reject(err);
} else {
// 任务成功
resolve(data);
}
})
});
var p3 = new Promise(function (resolve, reject) {
fs.readFile('c.txt', 'utf8', function (err, data) {
// 任务失败
if (err) {
// 把容器的pending状态改为Rejected
// 相当于调用then第二个参数
reject(err);
} else {
// 任务成功
resolve(data);
}
})
});
// 当p1成功了,然后做指定的操作
// then方法第一个参数接收的function就是容器中的resolve函数
// 当return 一个promise对象的对象,后续的then中的方法的第一个参数会作为p2的resolve
p1.then(function (data) {
console.log(data);
return p2;
}, function (err) {
console.log(err);
}).then(function (data) {
console.log(data);
return p3;
}).then(function (data) {
console.log(data);
});
/**
* 输出
* aaaaaaaaaa
* bbbbbbbbbbbb
* cccccccccc
*/
以上代码冗余代码很多,因而一般会进行封装:
var fs = require('fs');
function pReadFile(filePath) {
return new Promise(function (resolve, reject) {
fs.readFile(filePath, 'utf8', function (err, data) {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
}
pReadFile('a.txt').then(function (data) {
console.log(data);
return pReadFile('b.txt');
}).then(function (data) {
console.log(data);
return pReadFile('c.txt');
}).then(function (data) {
console.log(data);
});
API
文件系统(fs)
在Node中如果想要进行文件操作,就必须引入 fs 这个核心模块。
fs是file-system的简写,即文件系统,它提供了所有文件操作相关的API。
- fs.readFile(path[, options], callbcak)
- 读取文件内容。
- path:文件名
- options:字符编码
- callback:回调函数
- error:如果读取失败,error就是错误对象,成功则是null。
- data:如果读取成功,data就是读取到的数据,失败则是null。
- fs.writeFile(file, data[, options], callback)
- 写入数据到文件
- file:地址及文件名
- data:数据
- options:字符编码
- callback:回调函数
- error:如果写入失败,error就是错误对象,成功则是null。
- fs.readdir(path[, options], callback)
- 读取一个目录的内容。
- path:目录地址。
- options:字符编码。
- callback:回调函数,含有err和data参数
var fs = require('fs');
// 写入数据
fs.writeFile('hello.txt', '大家好,你是猪', function (error) {
if (error) {
console.log('文件写入失败');
return;
}
console.log('文件写入成功');
});
HTTP
-
http.createServer([options][, requestListener])
- 创建web服务器,返回server对象。
-
server.listen(handle[, callback])
- 绑定端口号,启动服务器。
- handle:端口号
-
response.write(chunk,[, encoding][, callback])
- 发送响应体数据块 。(不推荐)
- chunk:字符串数据
- encoding:字符编码
- callback
-
response.end([data][, encoding][, callback])
- 该方法会通知服务器,所有响应头和响应主体都已被发送,即服务器将其视为已完成。 (推荐)
- data:字符串数据
- encoding:字符编码
-
response.statusCode
- 该属性控制响应头刷新时将被发送到客户端的状态码。
- 301:永久重定向,浏览器会记住。
- 302:临时重定向,浏览器不会记住。
-
respon.setHeader(name, vallue)
-
为一个隐式的响应头设置值。
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
-
var http = require('http');
var fs = require('fs');
var server = http.createServer();
server.on('request', function (req, res) {
var url = req.url;
if (url === '/'){
fs.readFile('../../Sy8/1.html', function (err, data) {
if (err) {
res.setHeader('Content-Type', 'text/plain; charset=utf-8');
res.end('文件读取失败,请稍后重试!');
} else {
res.setHeader('Content-Type', 'text/html; charset=utf-8');
res.end(data);
}
});
}
});
server.listen(3000, function () {
console.log('Server is running...');
});
URL
- url.parse(urlString[, parseQueryString[, slashesDenoteHost]])
- urlstring:要解析的 URL 字符串。
- parseQueryString: 如果为
true
,则query
属性总会通过querystring
模块的parse()
方法生成一个对象。 如果为false
,则返回的 URL 对象上的query
属性会是一个未解析、未解码的字符串。 默认为false
。 - slashesDenoteHost : 如果为
true
,则//
之后至下一个/
之前的字符串会被解析作为host
。 默认false。
Path
- path.basename(path[, ext])
- 返回一个
path
的最后一部分 。 - path:路径
- ext:文件扩展名
- 返回一个
- path.dirname(path)
- 返回
path
的目录名。
- 返回
- path.extname(path)
- 返回
path
的扩展名。
- 返回
- path.isAbsolute(path)
- 判断
path
是否为一个绝对路径。
- 判断
- path.parse(path)
- 返回一个对象,对象的属性表示
path
的元素。
- 返回一个对象,对象的属性表示
- path.join([…paths])
- 使用平台特定的分隔符把全部给定的
path
片段连接到一起,并规范化生成的路径。 长度为零的path
片段会被忽略。 如果连接后的路径字符串是一个长度为零的字符串,则返回'.'
,表示当前工作目录。 - …paths:一个路径片段的序列
- 使用平台特定的分隔符把全部给定的
服务端渲染(使用模板引擎)
- node.js也可以使用模板引擎。
- 模板引擎不关心字符串的内容,只关心标记语法。
客户端渲染与服务端渲染区别
- 客户端渲染(利用Ajax与模板引擎),在浏览器查看源代码看不到。
- 服务端渲染是渲染好了再发给客户端,在源代码中看得到。
- 客户端渲染不利于SEO搜索引擎优化。
- 服务端渲染可被爬虫抓到,客户端异步渲染不行。
例:
var http = require('http');
var server = http.createServer();
var fs = require('fs');
// 引入模板引擎
var template = require('art-template');
var wwwDir = 'E:/Sourcecode/HTMLcode/Sy9';
server.on('request', function (req, res) {
var url = req.url;
fs.readFile('template-apache.html', function (err, data) {
if (err) {
return res.end('404 Not Found.');
}
fs.readdir(wwwDir, function (err, files) {
if (err) {
return res.end('Can not find www dir.');
}
// data默认为二进制数据,需要转换为字符串
var htmlStr = template.render(data.toString(), {
title: '哈哈',
files: files
});
res.end(htmlStr);
});
});
});
server.listen(3000, function () {
console.log('running');
});
template-apache.html
<html dir="ltr" lang="zh" i18n-processed="">
<head>
<meta charset="utf-8">
<meta name="google" value="notranslate">
<style>
h1 {
border-bottom: 1px solid #c0c0c0;
margin-bottom: 10px;
padding-bottom: 10px;
white-space: nowrap;
}
table {
border-collapse: collapse;
}
th {
cursor: pointer;
}
td.detailsColumn {
-webkit-padding-start: 2em;
text-align: end;
white-space: nowrap;
}
a.icon {
-webkit-padding-start: 1.5em;
text-decoration: none;
}
a.icon:hover {
text-decoration: underline;
}
a.file {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABnRSTlMAAAAAAABupgeRAAABHUlEQVR42o2RMW7DIBiF3498iHRJD5JKHurL+CRVBp+i2T16tTynF2gO0KSb5ZrBBl4HHDBuK/WXACH4eO9/CAAAbdvijzLGNE1TVZXfZuHg6XCAQESAZXbOKaXO57eiKG6ft9PrKQIkCQqFoIiQFBGlFIB5nvM8t9aOX2Nd18oDzjnPgCDpn/BH4zh2XZdlWVmWiUK4IgCBoFMUz9eP6zRN75cLgEQhcmTQIbl72O0f9865qLAAsURAAgKBJKEtgLXWvyjLuFsThCSstb8rBCaAQhDYWgIZ7myM+TUBjDHrHlZcbMYYk34cN0YSLcgS+wL0fe9TXDMbY33fR2AYBvyQ8L0Gk8MwREBrTfKe4TpTzwhArXWi8HI84h/1DfwI5mhxJamFAAAAAElFTkSuQmCC ") left top no-repeat;
}
a.dir {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAd5JREFUeNqMU79rFUEQ/vbuodFEEkzAImBpkUabFP4ldpaJhZXYm/RiZWsv/hkWFglBUyTIgyAIIfgIRjHv3r39MePM7N3LcbxAFvZ2b2bn22/mm3XMjF+HL3YW7q28YSIw8mBKoBihhhgCsoORot9d3/ywg3YowMXwNde/PzGnk2vn6PitrT+/PGeNaecg4+qNY3D43vy16A5wDDd4Aqg/ngmrjl/GoN0U5V1QquHQG3q+TPDVhVwyBffcmQGJmSVfyZk7R3SngI4JKfwDJ2+05zIg8gbiereTZRHhJ5KCMOwDFLjhoBTn2g0ghagfKeIYJDPFyibJVBtTREwq60SpYvh5++PpwatHsxSm9QRLSQpEVSd7/TYJUb49TX7gztpjjEffnoVw66+Ytovs14Yp7HaKmUXeX9rKUoMoLNW3srqI5fWn8JejrVkK0QcrkFLOgS39yoKUQe292WJ1guUHG8K2o8K00oO1BTvXoW4yasclUTgZYJY9aFNfAThX5CZRmczAV52oAPoupHhWRIUUAOoyUIlYVaAa/VbLbyiZUiyFbjQFNwiZQSGl4IDy9sO5Wrty0QLKhdZPxmgGcDo8ejn+c/6eiK9poz15Kw7Dr/vN/z6W7q++091/AQYA5mZ8GYJ9K0AAAAAASUVORK5CYII= ") left top no-repeat;
}
a.up {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmlJREFUeNpsU0toU0EUPfPysx/tTxuDH9SCWhUDooIbd7oRUUTMouqi2iIoCO6lceHWhegy4EJFinWjrlQUpVm0IIoFpVDEIthm0dpikpf3ZuZ6Z94nrXhhMjM3c8895977BBHB2PznK8WPtDgyWH5q77cPH8PpdXuhpQT4ifR9u5sfJb1bmw6VivahATDrxcRZ2njfoaMv+2j7mLDn93MPiNRMvGbL18L9IpF8h9/TN+EYkMffSiOXJ5+hkD+PdqcLpICWHOHc2CC+LEyA/K+cKQMnlQHJX8wqYG3MAJy88Wa4OLDvEqAEOpJd0LxHIMdHBziowSwVlF8D6QaicK01krw/JynwcKoEwZczewroTvZirlKJs5CqQ5CG8pb57FnJUA0LYCXMX5fibd+p8LWDDemcPZbzQyjvH+Ki1TlIciElA7ghwLKV4kRZstt2sANWRjYTAGzuP2hXZFpJ/GsxgGJ0ox1aoFWsDXyyxqCs26+ydmagFN/rRjymJ1898bzGzmQE0HCZpmk5A0RFIv8Pn0WYPsiu6t/Rsj6PauVTwffTSzGAGZhUG2F06hEc9ibS7OPMNp6ErYFlKavo7MkhmTqCxZ/jwzGA9Hx82H2BZSw1NTN9Gx8ycHkajU/7M+jInsDC7DiaEmo1bNl1AMr9ASFgqVu9MCTIzoGUimXVAnnaN0PdBBDCCYbEtMk6wkpQwIG0sn0PQIUF4GsTwLSIFKNqF6DVrQq+IWVrQDxAYQC/1SsYOI4pOxKZrfifiUSbDUisif7XlpGIPufXd/uvdvZm760M0no1FZcnrzUdjw7au3vu/BVgAFLXeuTxhTXVAAAAAElFTkSuQmCC ") left top no-repeat;
}
html[dir=rtl] a {
background-position-x: right;
}
#parentDirLinkBox {
margin-bottom: 10px;
padding-bottom: 10px;
}
#listingParsingErrorBox {
border: 1px solid black;
background: #fae691;
padding: 10px;
display: none;
}
</style>
<title id="title">{{ title }}</title>
</head>
<body>
<div id="listingParsingErrorBox">糟糕!Google Chrome无法解读服务器所发送的数据。请<a
href="http://code.google.com/p/chromium/issues/entry">报告错误</a>,并附上<a href="LOCATION">原始列表</a>。
</div>
<h1 id="header">D:\Movie\www\ 的索引</h1>
<div id="parentDirLinkBox" style="display:none">
<a id="parentDirLink" class="icon up">
<span id="parentDirText">[上级目录]</span>
</a>
</div>
<table>
<thead>
<tr class="header" id="theader">
<th onclick="javascript:sortTable(0);">名称</th>
<th class="detailsColumn" onclick="javascript:sortTable(1);">
大小
</th>
<th class="detailsColumn" onclick="javascript:sortTable(2);">
修改日期
</th>
</tr>
</thead>
<tbody id="tbody">
{{each files}}
<tr>
<td data-value="apple/"><a class="icon dir" href="E:/Sourcecode/HTMLcode/Sy9">{{$value}}/</a></td>
<td class="detailsColumn" data-value="0"></td>
<td class="detailsColumn" data-value="1509589967">2017/11/2 上午10:32:47</td>
</tr>
{{/each}}
</tbody>
</table>
</body>
</html>
使用Node操作MySQL数据库
安装:
npm i mysql
使用:
var mysql = require('mysql');
// 创建连接
var connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'root',
database: 'my_db'
});
// 连接数据库
connection.connect();
// 执行数据操作,增删改查都是用query
connection.query('SELECT 1 + 1 AS solution', function (error, results, fields) {
if (error) throw error;
console.log('The solution is: ', results[0].solution);
});
// 关闭连接
connection.end();
在Node中操作MongoDB(了解)
mongoDB 数据库的基本概念
- 数据库
- 集合(表)
- 文档(表记录)
{
qq:{ // 数据库
users:[ // 集合
{name: ''}, // 文档
{name: ''},
...
]
}
}
使用官方的 mongodb
包来操作
使用第三方mongoose来操作MongoDB 数据库
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
// 连接数据库
mongoose.connect('mongodb://localhost/test');
// 设计集合结构(表结构)
// 字段名称就是表结构中的属性名称
var blogSchma = new Schama({
username: {
type: String,
required: true // 非空
}
});
// 将文档结构发布为模型,返回模型构造函数
// 第一个参数是集合名称(大写名称单数字符串,会自动转为小写复数)
// 第二个参数是架构
var User = mongoose.model('User', blogSchma);
// 实例化一个 User
var kitty = new User({ name: 'Zildjian' });
// 持久化保持kitty实例
kitty.save(function (err, ret) {
if (err) {
console.log('err');
} else {
console.log(ret);
}
});
Express(重要)
起步
安装
npm install --save express
API
- express.static(code)
- 设置响应的HTTP状态。
- req.query
- 此属性是一个对象,包含路由中每个查询字符串参数的属性。如果没有查询字符串,则它是空对象
{}
。即返回get请求过来的数据对象。
- 此属性是一个对象,包含路由中每个查询字符串参数的属性。如果没有查询字符串,则它是空对象
- res.redirect([status,] path)
- 重定向到从指定的URL派生的URL
path
,具有指定的status
与HTTP状态代码对应的正整数。如果未指定,则status
默认为“302”Found“。
- 重定向到从指定的URL派生的URL
初使用
var express = require('express');
// 创建服务器,也就是http.createServer
var app = express();
// 公开指定目录,可以直接通过/public/xx访问public目录中的所有资源
app.use('/public/', express.static('./public/'));
// 当服务器收到get请求 / 的时候,执行回调函数
app.get('/', function (req, res) {
// 响应数据
res.send('hello express!');
});
app.get('/about', function (req, res) {
res.send('你好,我是express!');
});
// 相当于 server.listen
app.listen(3000, function () {
console.log('app is running at port 3000.');
});
基本路由
get:
app.get('/', function (req, res){
res.send('Hello');
});
post:
app.post('/', function (req, res){
res.send('world');
});
静态服务
// 当省略第一个参数的时候,则可以通过 省略 /public 的方式来访问,如127.0.0.1:3000/index.html<==>127.0.0.1:3000/public/index.html
app.use(express.static('/public/'));
// 当以 /public/ 开头的时候, 去 public 目录 目录找对应资源127.0.0.1:3000/static/index.html(推荐这种方式)
app.use('/public', express.static('public'));
app.use('/public', express.static(path.join(__dirname, 'public')));
在Express中配置使用 art-template
模板引擎
安装:
npm install --save art-template
npm install --save express-atr-template
配置
// 核心代码,配置使用art-template模板引擎,当渲染以 .art 结尾的文件的时候,使用atr-template模板引擎。
app.engine('art', require('express-art-template'));
// 如果想要修改默认的 views 视图渲染存储目录, 则可以
// app.set('views', render函数的默认路径);
使用
// res.render('html模板名', {模板数据});
// 第一个参数不能写路径,默认会去项目中的 views 目录查找该模板文件。
app.get('/', function (req, res) {
res.render('index.art', {
user: {
name: 'aui',
tags: ['art', 'template', 'nodejs']
}
});
});
在Express获取表单 POST 请求体数据
在Express中没有内置获取POST请求你体的API,需要使用第三方包:body-parser
。
安装:
npm install --save body-parser
配置:
var express = require('express');
// 引包
var bodyParser = require('body-parser');
var app = express();
// 配置body-parser
// 只要加入这个配置,则在req请求对象上会多出来一个属性:body
// 可以直接通过 req.body 来获取表单POST提交的数据
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }));
// parse application/json
app.use(bodyParser.json());
使用:
app.use(function (req, res) {
res.setHeader('Content-Type', 'text/plain');
res.write('you posted:\n');
res.end(JSON.stringify(req.body, null, 2));
})
**注意:**表单具有默认的提交行为,默认是同步的,同步表单提交,浏览器会锁死等待服务端的响应结果。表单的同步提交之后,无论服务端响应是什么,都会直接把响应的结果覆盖掉当前页面。
服务器重定向针对异步请求无效。
在Express配置使用express-session
插件
安装:
npm install express-session
配置:
app.use(session({
// 配置加密字符串,它会在原有加密基础之上和这个字符串拼起来去加密
// 目的是为了增加安全性
secret: 'itcast',
resave: false,
// 无论是否使用session,都默认直接给你配一把钥匙
saveUninitialized: true
}));
使用:
// 可以通过req.session来访问和设置Session成员
// 添加Session数据:
req.session.foo = 'bar';
// 访问Session数据:
req.session.foo
提示:默认Session数据是内存存储的,服务器一旦重启就会丢失,真正的生产环境会把Session持久化存储。
中间件
-
不关心请求路径和请求方法的中间件(即任何请求都会进入的中间件)
app.use (function (req, res, next) { // 接收三个参数,req请求对象,response响应对象,next下一个中间件(也需要相匹配的) console.log('1'); next(); });
当一个请求进入一个中间件之后,如果不调用next()则停留在当前中间件。
-
以 /xxx 开头的路径中间件
app.use('/a', function (req, res, next) { console.log(req.url); });
-
严格匹配请求方法和请求路径的中间件
app.get(); app.post();
-
内置中间件
- express.static
- express.json
- express.urlencoded
-
第三方中间件
- body-parser
- compression
- cookie-parser
- serve-static
路由器
路由器的行为类似于中间件本身,因此您可以将其用作 app.use() 的参数或作为另一个路由器的 use() 方法的参数。
顶级express
对象具有一个用于创建新对象的Router()方法router
。
一旦你创建了一个路由器的对象,你可以添加中间件和HTTP方法路由(如get
,put
,post
,等),以它就像一个应用程序。例如:
一般用于模块化处理地址。
// a.js
var router = express.Router();
router.get('/', function(){
// ...
});
router.post('/', function(){
// ...
});
module.exports = router;
// b.js 程序入口
var app = express();
var fun = require('./a.js');
// 把路由容器挂载到 app服务中
app.use(fun);