node.js介绍
Node.js是什么
- Node.js 是 JavaScript 运行时环境
- 通俗易懂的讲,Node.js 是 JavaScript 的运行平台
- Node.js 既不是语言,也不是框架,它是一个平台
- 浏览器中的 JavaScript
- EcmaScript
- 基本语法
- if
- var
- function
- Object
- Array
- Bom
- Dom
- Node.js 中的 JavaScript
- 没有Bom,Dom
- EcmaScript
- 在 Node 中这个 JavaScript 执行环境为 JavaScript 提供了一些服务器级别的 API
- 例如文件的读写
- 网络服务的构建
- 网络通信
- http 服务器
- 构建与 Chrome 的 V8 引擎之上
- 代码只是具有特定格式的字符串
- 引擎可以认识它,帮你解析和执行
- Google Chrome 的 V8 引擎是目前公认的解析执行 JavaScript 代码最快的
- Node.js 的作者把 Google Chrome 中的 V8 引擎移植出来,开发了一个独立的 JavaScript 运行时环境
- Node.js uses an envent-driven,non-blocking I/O mode that makes it lightweight and efficent.
- envent-driven 事件驱动
- non-blocking I/O mode 非阻塞I/O模型(异步)
- ightweight and efficent. 轻量和高效
- Node.js package ecosystem,npm,is the larget scosystem of open sourcr libraries in the world
- npm 是世界上最大的开源生态系统
- 绝大多数 JavaScript 相关的包都存放在 npm 上,这样做的目的是为了让开发人员更方便的去下载使用
npm install jquery
Node能做什么
- web服务器后台
- 命令行工具
- npm(node)
- git(c语言)
- hexo(node)
- …
- 对于前端工程师来讲,接触最多的是它的命令行工具
- 自己写的很少,主要是用别人第三方的
- webpack
- gulp
- npm
使用Node
安装Node环境
- 下载: https://nodejs.org/en/
- 安装:
- 傻瓜式安装,一直
next
就行 - 安装过再次安装会升级
- 确认 Node 环境是否安装成功
- 查看 node 的版本号:
node --version
- 或者
node -v
- 配置环境变量
解析执行JavaScript
- 创建编写JavaScript脚本文件
- 打开终端,定位脚本文件的所属目录
- 输入
node 文件名
执行对应的文件
注意:文件名不要用 node.js
来命名,最好不要使用中文。
模块系统
- 核心模块
- fs 文件操作模块
- http 网络服务构建模块
- os 操作系统信息模块
- path 路径处理模块
- 用户自定义模块
- 通过require(‘路径’) 加载模块,例如:require(‘./b.js’),
相对路径 ./ 不能省略
- 可以省略文件后缀名,默认 .js
- 通过require(‘路径’) 加载模块,例如:require(‘./b.js’),
- 第三方模块
- art-template
- 必须通过npm来下载才可以使用
CommonJS模块规范
- 模块作用域
- 使用 require 方法来加载模块
- 使用 exports 接口对象来导出模板中的成员
加载(require)
语法:
var 自定义变量名 = require('模块')
作用:
- 执行被加载模块中的代码
- 得到被加载模块中的
exports
导出接口对象
导出(exports)
- Node 中是模块作用域,默认文件中所有的成员只在当前模块有效
- 对于希望可以被其他模块访问到的成员,我们需要把这些公开的成员都挂载到
exports
接口对象中就可以了
导出多个成员(必须在对象中):
exports.a = 123;
exports.b = 'hello';
exports.c = function(){
console.log('bbb')
};
exports.d = {
foo:"bar"
};
导出单个成员:
module.exports = 'hello';
// 后者会覆盖前者
module.exports = function add(x,y) {
return x+y;
}
也可以通过以下方法来导出多个成员:
module.exports = {
foo = 'hello',
add:function(){
return x+y;
}
};
原理
在node中,每个模块内部都有一个自已的 module 对象
在 module 对象中,有一个成员 exports 也是一个对象
module = {
exports = {
}
}
当给exports重新赋值后,exports!= module.exports.
最终return的是module.exports,无论exports中的成员是什么都没用。
exports是 module.exports
的一个引用:
console.log(exports === module.exports); // true
exports.foo = 'bar';
//等价于
module.exports.foo = 'bar';
真正去使用的时候:
- 导出单个成员:module.exports = xxx; // 获取的是
- 导出多个成员:module.exports.xxx 或者 modeule.exports = {};
exports == module.exports
用来重新建立关系
require方法加载规则
- 优先从缓存加载(不会重复加载)
- 判断模块标识符
- 核心模块
- 用户自定义模块(以路径形式加载)
- 第三方模块
- 先找到当前文件所处目录中的 node_modules 目录
- node_modules/art-template(模块名)
- node_modules/art-template/package.json 文件
- node_modules/art-template/package.json 文件中的 main 属性
- main 属性中就记录了 art-template 的入口模块
- 然后加载使用这个第三方包
- 如果 package.json 文件不存在或者 main 指定的入口模块也没有
- 则 node 会默认找该目录下的 Index.js
- 如果以上任何一个条件都不成立,则会进入上一级目录按以上规则查找
- 直到磁盘根目录,最后报错
npm
node package manage(node包管理器)
npm 官网
npm 命令行工具
npm 是一个命令行工具,只要安装了 node 就已经安装了 npm。
npm 也有版本概念,可以通过 npm --version
来查看npm的版本
升级npm: npm install --global npm
常用命令
- npm init 生成package.json说明书文件
- npm init -y 可以跳过向导,快速生成
- npm install
- dependencies选项中的依赖项全部安装
- npm i
- npm install 包名
- 只下载
- npm i 包名
- npm install —save 包名
- 下载并且保存依赖项 package.json文件中的dependencies选项
- npm i 包名
- npm uninstall 包名
- 只删除,如果有依赖项会依然保存
- npm un 包名
- npm uninstall —save 包名
- 删除的同时也会把依赖信息全部删除
- npm un 包名
- npm help
- 查看使用帮助
- npm 命令 —help
- npm uninstall —help 查看具体命令的使用帮助
npm 速度慢
方法1
淘宝的开发团队把npm在国内做了一个 镜像。
安装淘宝的cnpm:
npm install --global cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org
#在任意目录执行都可以
#--global表示安装到全局,而非当前目录
#--global不能省略,否则不管用
npm install --global cnpm
安装包的时候把以前的 npm
替换成 cnpm
#走国外的 npm 服务器下载 jQuery 包,速度比较慢
npm install jQuery
#使用 cnpm 就会通过淘宝的服务器来下载 jQuery
cnpm install jQuery
如果不想安装 cnpm
又想使用淘宝的服务器来下载:
npm install jquery --registry=https://npm.taobao.org;
但是每次手动加参数就很麻烦,所以我们可以把这个选项加入到配置文件中:
npm config set registry https://npm.taobao.org;
#查看 npm 配置信息
npm config list;
只要经过上面的配置命令,则以后所有的 cnpm install
都会通过淘宝的服务器来下载
方法2
使用 码云(gitee)作为中转站
- 从 GitHub / GitLab 导入仓库
- 复制 GitHub 地址
- 导入 gitee 仓库
- 下载
方法3
在 GitHub 地址后面添加 cnpmjs.org
例如: https://github.com/jackfrued/Python-100-Days.git
修改后: https://github.com.cnpmjs.org/jackfrued/Python-100-Days.git
然后 clone 下载
方法4
适合下载单个文件
使用 jsdelivr提供的免费 cdn 加速
例如: https://github.com/stevenjoezhang/live2d-widget/blob/master/README.md
修改后: https://cdn.jsdelivr.net/gh/stevenjoezhang/live2d-widget@master/README.md
package.json
每一个项目都要有一个 package.json
文件(包描述文件,就像产品的说明书一样)
这个文件可以通过 npm init
自动初始化出来
dependencies
选项,可以用来帮助我们保存第三方包的依赖信息。
如果 node_modules
删除了也不用担心,只需要在控制面板中 npm install
就会自动把 package.json
中的 dependencies
中所有的依赖项全部都下载回来。
- 建议每个项目的根目录下都有一个
package.json
文件 - 建议执行
npm install 包名
的时候都加上--save
选项,目的是用来保存依赖信息
package-lock.json
npm 5以前是不会有 package-lock.json
这个文件
npm5以后才加入这个文件
当你安装包的时候,npm都会生成或者更新 package-lock.json
这个文件
- npm5以后的版本安装都不要加
--save
参数,它会自动保存依赖信息 - 当你安装包的时候,会自动创建或者更新
package-lock.json
文件 package-lock.json
这个文件会包含node_modules
中所有包的信息(版本,下载地址…)- 这样的话重新
npm install
的时候速度就可以提升
- 这样的话重新
- 从文件来看,有一个
lock
称之为锁- 这个
lock
是用来锁版本的 - 如果项目依赖了
1.1.1
版本 - 如果你重新 install 会下载最新版本,而不是
1.1.1
- package-lock.json 的另外一个作用就是锁定版本号,防止自动升级
- 这个
核心模块使用
文件的读写
// 1.使用fs核心模块
var fs = require('fs');
// 2.读取文件
// 第一个参数就是要读取的文件路径
// 第二个参数是一个回调函数
// 成功
// data 数据
// err null
// 失败
// data undefined 没有数据
// err 错误对象
fs.readFile('./data/a.txt',function(err,data){
if(err){
console.log('文件读取失败');
}else{
// 文件中存储的都是二进制数据
// 通过toString()方法转换为我们能认识的字符
// 可以结合服务器通过读取文件来实现发送页面
console.log(data.toString());
}
})
// 3.将数据写入文件
// 第一个参数:文件路径
// 第二个参数:文件内容
// 第三个参数:回调函数
fs.writeFile('./data/a.txt','写入文件的内容',function(err){
if(err){
console.log('写入失败');
}
else{
console.log('写入成功');
}
})
HTTP服务
- 提供服务:对数据服务
- 发送请求
- 接收请求
- 处理请求
- 反馈(发送响应)
- 当客户端请求过来,就会自动触发服务器的request请求事件,然后执行第二个参数:回调处理函数
// 1.加载http核心模块
var http = require('http');
var fs = require('fs');
// 2.使用http.createServer()创建一个web服务器
var server = http.createServer();
// 读取文件时的根目录
var wwwDir = 'D:/app/www'
// 3.触发服务器的request请求事件
// request 请求事件处理函数,需要接收两个参数:
// request 请求对象
// 请求对象可以用来获取客户端的一些请求信息,例如请求地址
// response 响应对象
// 响应对象可以用来给客户端发送响应消息
server.on('request', function (req, res) {
// 获取当前 url(端口号后面的路径)
var url = req.url
// 默认为 /index.html
var filePath = '/index.html'
// 如果不是默认 url,则获取当前用户输入的 url
if (url !== '/') {
filePath = url
}
// 读取文件
fs.readFile(wwwDir + filePath, function (err, data) {
if (err) {
// 响应内容只能是字符串或二进制数据
// 告诉浏览器发送的是什么类型的内容
// 图片不需要指定编码
response.setHeader('Content-Type', 'text/html; charset=utf-8')
return res.end('404 NOT Found')
}
res.end(data)
})
})
// 4.绑定端口号,启动服务
server.listen(3000, function () {
console.log('running')
})
path路径操作模块
参考文档: https://nodejs.org/dist/latest-v14.x/docs/api/path.html
- path.basename:获取路径的文件名,默认包含扩展名
- 第二个参数传一个文件扩展名获取到的文件名就不包含扩展名
- path.dirname:获取路径中的目录部分
- path.extname:获取一个路径中的扩展名部分
- path.isAbsolute:判断一个路径是否为绝对路径
- path.parse:把路径转换为对象
- root:根路径
- dir:目录
- base:包含扩展名的文件名
- ext:扩展名
- name:不包含扩展名的文件名
- path.join:拼接路径
模版使用
浏览器中使用模板
安装
npm install --save art-template
使用
<script src="./node_modules/art-template/lib/template-web.js"></script>
<script type="text/template" id="tpl">
大家好,我叫:{{ name }}
我今年 {{ age }} 岁了
我来自 {{ province }}
我喜欢:{{ each hobbies }} {{ $value }} {{ /each }}
</script>
<script>
var ret = template('tpl', {
name: 'Jack',
age: 18,
province: '北京市',
hobbies: [
'写代码',
'唱歌',
'打游戏'
]
})
// ret 只是渲染后的内容,需要写进页面才会显示
console.log(ret);
</script>
node中使用模板
安装
npm install --save art-template
使用
// 引用模板模块
var template = require('art-template')
var fs = require('fs')
fs.readFile('./tpl.html', function (err, data) {
if (err) {
console.log('读取失败')
}
// 转换为字符串
var data = data.toString()
// 模板渲染
var ret = template.render(data, {
name: 'Jack',
age: 18,
province: '北京市',
hobbies: [
'写代码',
'唱歌',
'打游戏'
]
})
console.log(ret)
})
tpl.html
<p>大家好,我叫:{{ name }}</p>
<p>我今年 {{ age }} 岁了</p>
<p>我来自 {{ province }}</p>
<p>我喜欢:{{ each hobbies }} {{ $value }} {{ /each }}</p>
Apche目录案例
// 1.加载http核心模块
var http = require('http');
var fs = require('fs');
// 引入模板模块
var template = require('art-template')
// 2.使用http.createServer()创建一个web服务器
var server = http.createServer();
// 读取文件时的根目录
var wwwDir = 'D:/app/www'
// 3.触发服务器的request请求事件
server.on('request', function (req, res) {
// 读取模版页面
fs.readFile('./template-Apache.html', function (err, data) {
if (err) {
return res.end('404 NOt Fount.')
}
// 读取要显示的目录
fs.readdir(wwwDir, function (err, files) {
if (err) {
return res.end('Can not find www dir.')
}
// 使用模板引擎
var htmlStr = template.render(data.toString(), {
title: '哈哈',
files: files
})
// 发送解析过后的响应数据
res.end(htmlStr)
})
})
})
// 4.绑定端口号,启动服务
server.listen(3000, function () {
console.log('running')
})
template-Apache.html
<tbody id="tbody">
{{each files}}
<tr>
<td data-value="img/"><a class="icon dir" href="/D:/app/www/img/">{{$value}}</a></td>
<td class="detailsColumn" data-value="0"></td>
<td class="detailsColumn" data-value="1592877672">2020/6/23 上午10:01:12</td>
</tr>
{{/each}}
</tbody>
留言板案例
var http = require('http');
var fs = require('fs')
var url = require('url')
var template = require('art-template')
// 用来存放评论数据
var comments = [
{
name: '张三1',
message: '今天天气真好',
dateTime: '2020-6-24'
},
{
name: '张三2',
message: '今天天气真不错',
dateTime: '2020-6-24'
},
{
name: '张三3',
message: '今天天气真不错',
dateTime: '2020-6-24'
},
{
name: '张三4',
message: '今天天气真不错',
dateTime: '2020-6-24'
},
{
name: '张三5',
message: '今天天气真不错',
dateTime: '2020-6-24'
}
]
http
.createServer(function (req, res) {
var parseObj = url.parse(req.url, true)
// 获取路径名
var parsename = parseObj.pathname
if (parsename === '/') {
fs.readFile('./views/index.html', function (err, data) {
if (err) {
return res.end('404 Not Found.')
}
// 模板渲染
var data = template.render(data.toString(), {
comments: comments
})
res.end(data)
})
} else if (parsename === '/post') {
fs.readFile('./views/post.html', function (err, data) {
if (err) {
return res.end('404 Not Found.')
}
res.end(data)
})
// 表单属性 action="/pinglun"
} else if (parsename === '/pinglun') {
// 获取 get 请求数据
var comment = parseObj.query
comment.dateTime = '2020-7-11 17:27:14'
// 添加到评论数组对象中
comments.unshift(comment)
// 重定向
// 状态码设置为 301 永久重定向
// 状态码设置为 302 临时重定向
// 在响应头中通过 location 告诉客户端往哪儿重定向
res.statusCode = 302
res.setHeader('Location', '/')
// 结束响应
res.end()
// 开放目录
} else if (parsename.indexOf('/public/') == 0) {
fs.readFile('.' + parsename, function (err, data) {
if (err) {
return res.end('404 Not Found.')
}
res.end(data)
})
} else {
fs.readFile('./views/404.html', function (err, data) {
if (err) {
return res.end('404 Not Found.');
}
res.end(data);
})
}
})
// 4.绑定端口号,启动服务
.listen(1314, function () {
console.log('服务器启动成,通过localhost:3000/来进行访问')
})
index.html
<ul class="list-group">
<!-- 遍历对象数组并渲染 -->
{{each comments}}
<li class="list-group-item">{{ $value.name }}说:{{ $value.message }}</li>
{{/each}}
</ul>
开放目录之后页面中的引入文件(如:link 标签和 script 标签)将不需要用相对路径引用,例如:<link rel="stylesheet" href="/public/lib/bootstrap/css/bootstrap.min.css">
/
表示的是服务器根目录
Node中的其它成员
在每个模块中,除了 require
, exports
等模块相关的API之外,还有两个特殊的成员:
__dirname
,可以用来 动态 获取当前文件模块所属目录的绝对路径(不包含文件名)__filename
,可以用来 动态 获取当前文件的绝对路径(包含文件名)__dirname
和filename
是不受执行 node 命令所属路径影响的
在文件操作中,使用相对路径是不可靠的,因为node中文件操作的路径被设计为相对于执行node 命令所处的终端路径。
所以为了解决这个问题,只需要把相对路径变为绝对路径(绝对路径不受任何影响)就可以了。
就可以使用 __dirname
或者 __filename
来帮助我们解决这个问题
在拼接路径的过程中,为了避免手动拼接带来的一些低级错误,推荐使用 path.join()
来辅助拼接
模块中的路径标识和这里的路径没关系,不受 node 命令执行所处目录影响(相对于文件模块)
var fs = require('fs');
var path = require('path');
// console.log(__dirname + 'a.txt');
// path.join方法会将文件操作中的相对路径都统一的转为动态的绝对路径
fs.readFile(path.join(__dirname + '/a.txt'),'utf8',function(err,data){
if(err){
throw err
}
console.log(data);
});
补充:模块中的路径标识和这里的路径没关系,不受影响(就是相对于文件模块) 注意: 模块中的路径标识和文件操作中的相对路径标识不一致 模块中的路径标识就是相对于当前文件模块,不受node命令所处路径影响
Express(快速的)
其中主要封装的是http
// 0. 安装
// 1. 引包
var express = require('express');
// 2 创建服务器应用程序
// 也就是原来的http.createServer();
var app = express();
// 公开指定目录
// 这样就能通过 /public/xx 的方式来访问 public 目录中的所有资源
// 在 Express中开放资源就是一个 API 的事
app.use('/public/',express.static('./public/'));
//模板引擎在 Express 中开放模板也是一个 API 的事
// 当服务器收到 get 请求 / 的时候,执行回调处理函数
// 使用 res.send 就不需要考虑编码问题
// 在 Express 中可以直接使用 req.query 来获取查询字符串参数
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 runing at port 3000');
})
起步
安装
npm install express --save
hello world
var express = require('express');
var app = express();
app.get('/',function(req,res){
res.send('hello world');
})
app.listen(3000,function(){
console.log('express app is runing...');
})
基本路由
路由
- 请求方法
- 请求路径
- 请求处理函数
get
//当你以 get 方法请求/的时候,执行对应的处理函数
app.get('/',function(req,res){
res.send('hello world');
})
post
//当你以 post 方法请求/的时候,执行对应的处理函数
app.post('/',function(req,res){
res.send('hello world');
})
静态服务
// 开放目录
app.use('/public/',express.static('./public/'));
// 当省略第一个参数的时候,则 url 可以省略 /public 来访问
app.use(express.static('./public/'));
// a 相当于 public 的别名,通过 /a/文件名 来访问 public 目录下的文件
app.use('/a/',express.static('./public/'));
使用art-template模板引擎
- art-template官方中文文档
- 在node中,有很多第三方模板引擎都可以使用,不是只有
art-template
- 还有ejs,jade(pug),handlebars,nunjucks
安装
c npm install --save art-template
c npm install --save express-art-template
// 同时安装两个时用空格隔开
c npm i --save art-template express-art-template
配置
// 表示当渲染 .art 文件时,使用 art-template 模板引擎,使用 .art 只是为了更好辨别
// express-art-template 是专门用来在 express 中使用的 art-template
// 因为 express-art-template 依赖了 art-template ,所以不加载也必须安装
// app.engine('art', require('express-art-template'));
app.engine('html', require('express-art-template'))
使用
app.get('/',function(req,res){
// 第一个参数不能写路径,默认会去 views 目录找 index.html
res.render('admin/index.html',{
title:'hello world'
});
})
如果想要修改默认的 views 视图渲染存储目录,可以:
// 第一个参数 views千万不要写错
app.set('views', 默认路径);
日期格式化
https://blog.csdn.net/qincidong/article/details/82252298 https://www.cnblogs.com/HJ412/p/11495588.html
获取表单请求体数据
获取GET请求数据
Express内置了一个api,可以直接通过 req.query
来获取数据
// 通过requery方法获取用户输入的数据
// req.query只能拿到get请求的数据
var comment = req.query;
获取POST请求数据
在Express中没有内置获取表单post请求体的api,这里我们需要使用中间件 body-parser
来获取数据。
安装
c npm install --save body-parser
配置
http://expressjs.com/en/resources/middleware/body-parser.html
配置解析表单 POST 请求体插件(注意:一定要在 app.use(router) 之前 )
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')
// 可以通过req.body来获取表单请求数据
res.end(JSON.stringify(req.body, null, 2))
})
session
安装
c npm i express-session --save
配置
// 该插件会为req请求对象添加一个成员 : req.session 默认是一个对象
// 这是最简单的配置方式
// Session 是基于 Cookie 实现的
app.use(session({
// secret 配置加密字符串,他会在原有的基础上和字符串拼接起来去加密
// 目的是为了增加安全性,防止客户端恶意伪造
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,// 无论是否适用 Session,都默认直接分配一把钥匙
}))
使用
//添加 Session 数据
//session 就是一个对象
req.session.foo = 'bar';
//获取 session 数据
req.session.foo
//删除 session 数据
req.session.foo = null;
delete req.session.foo
提示:
默认 Session 数据是内存储数据,服务器一旦重启就会丢失,真正的生产环境会把 Session 进行持久化存储。
CRUD 案例
实现步骤
- 处理模板
- 配置静态开放资源
- 配置模板引擎
- 简单的路由,/studens渲染静态页出来
- 路由设计
- 提取路由模块
- 由于接下来的一系列业务操作都需要处理文件数据,所以我们需要封装Student.js’
- 先写好 student.js 文件结构
- 查询所有学生列表的API
- findById
- save
- updateById
- deleteById
- 实现具体功能
- 通过路由收到请求
- 接受请求中的参数(get,post)
- req.query
- req.body
- 调用数据操作API处理数据
- 根据操作结果给客户端发送响应
- 业务功能顺序
- 列表
- 添加
- 编辑
- 删除
模块化
模块如何划分:
- 模块职责要单一
javascript模块化:
- Node 中的 CommonJS
- 浏览器中的:
- AMD require.js
- CMD sea.js
- es6中增加了官方支持
起步
- 初始化
- 安装依赖
- 模板处理
路由设计
请求方法 | 请求路径 | get参数 | post参数 | 备注 |
---|---|---|---|---|
GET | /students | 渲染首页 | ||
GET | /students/new | 渲染添加学生页面 | ||
POST | /students/new | name,age,gender,hobbies | 处理添加学生请求 | |
GET | /students/edit | id | 渲染编辑页面 | |
POST | /students/edit | id,name,age,gender,hobbies | 处理编辑请求 | |
GET | /students/delete | id | 处理删除请求 |
提取路由模块
router.js:
注:当封闭了学生信息操作模块时,以下代码需要进行整改
/**
* router.js路由模块
* 职责:
* 处理路由
* 根据不同的请求方法+请求路径设置具体的请求函数
* 模块职责要单一,我们划分模块的目的就是增强代码的可维护性,提升开发效率
*/
var fs = require('fs')
var Students = require('./students')
// Express 提供了一种专门用来 包装 路由的 方式
var express = require('express')
// 1 . 创建一个路由容器
var router = express.Router()
// 2 . 把路由都挂载到 router 路由容器中
/**
* 渲染学生列表页面
*/
router.get('/students', function(req, res) {
// readFile 第二个参数可选,传入 utf8 会 按照 utf8 转 换
// 也 能 通过 data.toString () 的方式 转换
fs.readFile('./db.json', 'utf8', function(err, data) {
if (err) {
return res.status(500).send('Server error.')
}
// 读取到的文件数据是 string 类型的数据
// 需要转换成对象
var students = JSON.parse(data).students;
res.render('index.html', {
students:students
})
})
});
/**
* 渲染学生添加页面
*/
router.get('/students/new',function(req,res){
res.render('new.html')
});
/**
* 处理添加学生
*/
router. pos t('/students/ n e w ', function (req, res) {
});
/**
* 渲染编辑学生页面
*/
router. ge t('/students/edit', function (req, res) {
});
/**
* 处理编辑学生
*/
router. pos t('/students/e di t', function (req, res) {
});
/**
* 处理删除学生
*/
router.get('/students/delete', function (req, res) {
});
// 3 把 router 导出
module.exports = router;
app.js:
/**
* app.js 入口模块
* 职责:
* 创建服务
* 做一些服务相关配置
* 模板引擎
* body-parser 解析表单 Post 请求体
* 提供静态资源服务
* 挂载路由
* 监听端口启动服务
*/
var express = require('express')
var router = require('./router .js ')
var bodyParser = require('body-parser')
var app = express()
// 开放目录
app.use(' / node_modules / ', exp r ess.static('./n o de_mod u les/'))
app.use('/public/', express.s t atic('./public/'))
// 配置模板引擎和 body-parser 一定要在 app.user(router) 挂载路由之前
app. e ngine('html', r equire ( 'express-art-template'))
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
// router(app)
// 把路由容器挂载到 app 服务中
app.use(router)
app.listen(1314, function (req, res) {
console.log('running 1314...')
})
设计操作数据的API文件模块
es6中的find和findIndex:
find接受一个方法作为参数,方法内部返回一个条件
find会便利所有的元素,执行你给定的带有条件返回值的函数
符合该条件的元素会作为find方法的返回值
如果遍历结束还没有符合该条件的元素,则返回undefined
/**
* student.js
* 数据操作文件模块
* 职责:操作文件中的数据,只处理数据,不关心业务
*/
var fs = require('fs')
/**
* 获取所有学生列表
* return []
*/
exports.find = function(){
}
/**
* 根据 id 获取学生信息对象(单个学生)
*/
exports.findById = function (id, callback) {
}
/**
* 获取添加保存学生
*/
exports.save = function(){
}
/**
* 更新学生
*/
exports.updat aById = function(){
}
/**
* 删除学生
*/
exports.delete ById = function(){
}
子模板和模板的继承(模板引擎高级语法)【include,extend,block】
注意:
模板页:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>模板页</title>
<link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.css"/>
{{ block 'head' }}{{ /block }}
</head>
<body>
<!-- 通过include导入公共部分 -->
{{include './header.html'}}
<!-- 留一个位置 让别的内容去填充 -->
{{ block 'content' }}
<h1>默认内容</h1>
{{ /block }}
<!-- 通过include导入公共部分 -->
{{include './footer.html'}}
<!-- 公共样式 -->
<script src="/node_modules/jquery/dist/jquery.js" ></script>
<script src="/node_modules/bootstrap/dist/js/bootstrap.js" ></script>
{{ block 'script' }}{{ /block }}
</body>
</html>
模板的继承:
header页面:
<div id="">
<h1>公共的头部</h1>
</div>
footer页面:
<div id="">
<h1>公共的底部</h1>
</div>
模板页的使用:
<!-- 继承(extend:延伸,扩展)模板也layout.html -->
<!-- 把layout.html页面的内容都拿进来作为index.html页面的内容 -->
{{extend './layout.html'}}
<!-- 向模板页面填充新的数据 -->
<!-- 填充后就会替换掉layout页面content中的数据 -->
<!-- style样式方面的内容 -->
{{ block 'head' }}
<style type="text/css">
body{
background-color: skyblue;
}
</style>
{{ /block }}
{{ block 'content' }}
<div id="">
<h1>Index页面的内容</h1>
</div>
{{ /block }}
<!-- js部分的内容 -->
{{ block 'script' }}
<script type="text/javascript">
</script>
{{ /block }}
MongoDB
关系型和非关系型数据库
关系型数据库。
表就是关系,或者说表与表之间存在关系
- 所有的关系型数据库都需要通过
sql
语言来操作 - 所有的关系型数据库在操作之前都需要设计表结构
- 而且数据表还支持约束
- 唯一的
- 主键
- 默认值
- 非空
非关系型数据库
- 非关系型数据库非常的灵活
- 有的关系型数据库就是 key-value(键值) 对儿
- 但 MongDB 是长得最像关系型数据库的非关系型数据库
- 数据库 -》 数据库
- 数据表 -》 集合(数组)
- 表记录 -》文档(对象)
- MongoDB 不需要设计表结构
- 可以任意的往里面存数据,没有结构性这么一说
基本结构
一个数据库中可以有多个数据库,一个数据库中可以有多个集合(数组),一个集合中可以有多个文档(表记录对象)
{
qq:{
user:[
{},{},{}...
]
...
}
....
}
安装
下载安装
下载地址
- https://www.mongodb.com/try/download/community
- 64 位下载地址: http://dl.mongodb.org/dl/win32/x86_64
- 32 位下载地址: http://dl.mongodb.org/dl/win32/i386
配置环境变量
和配置其它环境变量一样,配置 bin
目录
最后输入 mongod --version
测试是否安装成功(注意是 mongod)
教程和报错
- 教程: https://www.cnblogs.com/benyuanzhang/p/11060164.html
- 报错: https://blog.csdn.net/lhrdlp/article/details/106020109
启动和关闭数据库
启动
# mongodb 默认使用执行 mongod 命令所处 盘符 根目录下的/data/db作为自己的数据存储目录
# 所以在第一次执行该命令之前先自己手动新建一个 /data/db
mongod
如果想要修改默认的数据存储目录,可以:
mongod --dbpath = 数据存储目录路径
停止
在开启服务的控制台,直接Ctrl+C;
或者直接关闭开启服务的控制台。
连接和退出数据库
连接
# 该命令默认连接本机的 MongoDB 服务
mongo
退出
# 在连接状态输入 exit 退出连接
exit
基本命令
show dbs
- 查看所有数据库列表
db
- 查看当前连接的数据库
use 数据库名称
- 切换到指定的数据库(如果没有会新建)
- 只有插入数据后才会真正创建数据库
db.集合名.inserOne(对象)
- 插入数据
show collections
- 查看当前数据库下的所有集合(表)
db.集合名.find()
- 查看集合中的详细信息
在 Node 中操作 MongoDB 数据库
使用官方的 MongoDB 包
官方的比较原始,麻烦,所以不使用它
https://mongodb.github.io/node-mongodb-native https://github.com/mongodb/node-mongodb-native
使用 mongoose 包
第三方包: mongoose
基于MongoDB官方的 mongodb
包再一次做了封装,名字叫 mongoose
,是 WordPress 项目团队开发的。
- 官网: https://mongoosejs.com
- 官方计划: https://mongoosejs.com/docs/guide.html
- 官方 API 文档: https://mongoosejs.com/docs/api.html
- 官方入门指南: https://mongoosejs.com/docs/index.html
安装
cnpm i mongoose --save
hello word
const mongoose = require('mongoose');
// 连接 mongoDB 数据库
mongoose.connect('mongodb://localhost:27017/test', { useNewUrlParser: true, useUnifiedTopology: true });
// 创建一个模型(设计数据库)
const Cat = mongoose.model('Cat', { name: String });
// 实例化一个 Cat(会生成一个小写复数的集合)
const kitty = new Cat({ name: 'Zildjian' });
// 持久化保存 Kitty 实例
kitty.save().then(() => console.log('meow'));
设计 Scheme 发布 Model
des:相当于创建表结构
注意:设计集合结构时,对象名不能有大写(例如 userName )
// 1.引包
var mongoose = require('mongoose');
// 拿到 S chema 图表
var Schema = mongoose.Schema;
// 2.连接数据库
// 指定连接数据库后不需要存在,当你插入第一条数据库后会自动创建数据库
mongoose.connect('mongodb://localhost :27017 /test' , { useNewUrlParser: true, useUnifiedTopology: true } );
// 3.设计集合结构(表结构)
// 用户表
var userSchema = new Schema({
username: {
type: String,
require d : true //添加约束,保证数据的完整性,让数据按规矩统一
},
password: {
type: String,
require d : true
},
email: {
type: String
}
});
// 4.将文档结构发布为模型
// 第一个参数:大写单数 集合 名 (最终 会 转换为 小写复数集合名 ,表 名 )
// 第二个参数:架构 Schema(集合结构, 表结构)
// 返回值:模型构造函数
var User = mongoose.model('User', userSchema);
添加(增)
注 :版本不同可能 API 不同
// 5.通过模型构造函数对User中的数据进行操作
var user = new User({
username: 'admin',
password: '123456',
email: 'a dmin @qq.com'
});
user.save(function(err, ret) {
if (err) {
console.log('保存失败');
} else {
console.log('保存成功');
console.log(ret);
}
});
删除(删)
注 :版本不同可能 API 不同
根据条件删除所有:
User.remove({
username: ' zs '
}, function(err, ret) {
if (err) {
console.log('删除失败')
} else {
console.log('删除成功')
console.log(ret)
}
})
根据条件删除一个:
Model.findOneAndRemove(conditions,[options],[callback]);
根据id 删除一个:
Model .(id,[options],[callback]);
更新(改)
注 :版本不同可能 API 不同
更新所有:
Model . update (conditions, doc, [options], [callback]);
根据指定条件更新一个:
Mod e l . updateOn e([conditions], [update], [options],[callback]);
根据 id 更新一个:
// 更新 根据 id 来修改表数据
User.findByIdAndUpdate('5 f19 4f 80f a4 659521 8 e 5 7110 ', {
p a ssword : ' 123 '
}, function(err, ret) {
if (err) {
console.log('更新失败');
} else {
console.log('更新成功');
}
});
查询(查)
注 :版本不同可能 API 不同
查询所有:
// 查询所有
User.find(function(err,ret){
if(err){
console.log('查询失败');
}else{
console.log(ret);
}
});
条件查询所有:
// 根据条件查询 ,返回的是数组
User.find({ username:' zs ' },function(err,ret){
if(err){
console.log('查询失败');
}else{
console.log(ret);
}
});
条件查询单个:
// 按照条件查询单个, 返回的是对象
// 没有条件查询使用 findOne 方法,查询的是表中的第一条数据
User.findOne({
username: ' zs '
}, function(err, ret) {
if (err) {
console.log('查询失败');
} else {
console.log(ret);
}
});
通过 id 查询单个:
Model.findById(id,[options],[callback]);
使用Node操作MySQL数据库
文档:https://www.npmjs.com/package/mysql
安装:
c npm i mysql --save
// 引入mysql包
var mysql = require('mysql');
// 1. 创建连接
var connection = mysql.createConnection({
host : 'localhost', // 本机
user : 'me', // 账号root
password : 'secret', // 密码12345
database : 'my_db' // 数据库名
});
// 2. 连接数据库
connection.connect();
// 3. 执行数据操作
// 第一个参数写 sql 语句
connection.query('SELECT * FROM `users`', function (error, results, fields) {
if (error) throw error;// 抛出异常阻止代码往下执行
// 没有异常打印输出结果
console.log('The solution is: ',results);
});
// 4. 关闭连接
connection.end();
异步编程
回调函数
不成立的情况
function add(x,y){
console.log(1);
// setTimeout 是个异步 API
setTimeout(function(){
console.log(2);
var ret = x + y;
return ret;
},1000);
console.log(3);
//到这里执行就结束了,不会i等到前面的定时器,所以直接返回了默认值 undefined
}
console.log(add(2,2));
// 结果是 1 3 undefined 2
使用回调函数
也可以通过定义全局变量来获取异部数据,但那样函数封装就没有意义了
回调函数:通过一个函数,获取函数内部的操作。(根据输入得到输出结果)
function add(x, y, callback) {
// callback就是回调函数
// var x = 10;
// var y = 20;
// var callback = function(ret){console.log(ret);}
setTimeout(function () {
var ret = x + y;
callback(ret);
}, 1000);
}
add(10, 20, function (ret) {
console.log(ret);
});
注意
凡是需要得到一个函数内部异步操作的结果
- setTimeout
- readFile
- writeFile
- ajax
- readdir
这种情况必须通过回调函数 (异步 API 都会伴随着一个回调函数)
ajax
基于原生 XMLHttpRequest 封装 get 方法:
var oReq = new XMLHttpRequest();
// 当请求加载成功要调用指定的函数
oReq.onload = function(){
console.log(oReq.responseText);
}
oReq.open("GET", "请求路径", true);
oReq.send();
function get(url, callback){
var oReq = new XMLHttpRequest();
// 当请求加载成功要调用指定的函数
oReq.onload = function(){
callback(oReq.responseText);
}
oReq.open("GET", url, true);
oReq.send();
}
get('data.json', function(data){
console.log(data);
});
Promise
callback hell(回调地狱)
文件的读取无法判断执行顺序(文件的执行顺序是 可能 依据文件的大小来决定的),异步 api无法保证文件的执行顺序
var fs = require('fs');
fs.readFile('./data/a.txt','utf8',function(err,data){
if(err){
// 读取失败直接打印输出读取失败
return console.log('读取失败');
// 抛出异常
// 阻止程序的执行
// 把错误信息打印到控制台
throw err;
}
console.log(data);
});
fs.readFile('./data/b.txt','utf8',function(err,data){
if(err){
// 读取失败直接打印输出读取失败
return console.log('读取失败');
// 抛出异常
// 阻止程序的执行
// 把错误信息打印到控制台
throw err;
}
console.log(data);
});
通过回调嵌套的方式来保证顺序:
var fs = require('fs');
fs.readFile('./data/a.txt','utf8',function(err,data){
if(err){
// 1 读取失败直接打印输出读取失败
return console.log('读取失败');
// 2 抛出异常
// 阻止程序的执行
// 把错误信息打印到控制台
throw err;
}
console.log(data);
fs.readFile('./data/b.txt','utf8',function(err,data){
if(err){
// 1 读取失败直接打印输出读取失败
return console.log('读取失败');
// 2 抛出异常
// 阻止程序的执行
// 把错误信息打印到控制台
throw err;
}
console.log(data);
});
});
为了解决以上编码方式带来的问题(回调地狱嵌套),所以在 EcmaScript 6 新增了一个API: Promise
。
- Promise:承诺,保证
- Promise 是一个构造函数
- Pending、Resolved、Rejected 是容器 Promise 的状态
- Promise 本身不是异步的,但往往都是内部封装一个异步任务
Promise 基本语法
var fs = require('fs');
// 在EcmaScript 6中新增了一个API Promise
// Promise 是一个构造函数
// 1 . 创建 Promise 容器
// resolve: 解决
// reject:失败
var p1 = new Promise(function (resolve, reject) {
fs.readFile('./ data/ a.txt', 'utf8', function (err, data) {
if (err) {
// console.log(err);
// 把容器的 Pending 状态变为 rejected
// 调用的 reject 方法实际上就是 then 方法的第二个参数函数
reject(err);
} else {
// console.log(data);
// 把容器的 Pending 状态变为 resolve
// 调用的 resolve 方法实际上就是 then 方法传递的那个 function
resolve(data);
}
});
});
// 当 p1 成功了,然后(then)做指定的操作
// then 方法接收的 function 就是容器中的 resolve 函数
p1.
then(function (data) {
console.log(data);
}, function (err) {
cconsole.log('读取文件失败了', err);
})
图解
封装 Promise 的 readFile
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('./ data/ a.txt')
.then(function (data) {
console.log(data)
return pReadFile('./data/b.txt')
})
.then(function (data) {
console.log(data)
return pReadFile('./data/c.txt')
})
.then(function (data) {
console.log(data)
})
封装 Promise 的 ajax
var data = {}
function pGet(url, callback) {
return new Promise(function (resolve, reject) {
var oReq = new XMLHttpRequest();
oReq.onload = function () {
callback && callback(JSON.parse(oReq.responseText))
resolve(JSON.parse(oReq.responseText))
}
oReq.onerror(function (err) {
reject(err)
})
oReq.open("get", url, true)
oReq.send()
})
}
mongoose 中的 Promise
- 凡是操作数据库都是异步的
- mongoose 所有的 API 都支持 Promise
// 查询所有
User.find()
.then(function(data){
console.log(data)
})
注册:
User.findOne({ username: 'admin' }, function (user) {
if (user) {
console.log('用户已存在')
} else {
new User({
username: 'aaa',
password: '123',
email: 'fffff'
}).save(function () {
console.log('注册成功');
})
}
})
User.findOne({
username: 'admin'
})
.then(function (user) {
if (user) {
// 用户已经存在不能注册
console.log('用户已存在');
}
else {
// 用户不存在可以注册
return new User({
username: 'aaa',
password: '123',
email: 'fffff'
}).save();
}
})
.then(funciton(ret){
console.log('注册成功');
})
其他
修改完代码自动重启
我们在这里可以使用一个第三方命名行工具: nodemon
来帮助我们解决频繁修改代码重启服务器的问题。
nodemon
是一个基于Node.js开发的一个第三方命令行工具,我们使用的时候需要独立安装:
#在任意目录执行该命令都可以
#也就是说,所有需要 --global安装的包都可以在任意目录执行
npm install --global nodemon
npm install -g nodemon
#如果安装不成功的话,可以使用cnpm安装
cnpm install -g nodemon
安装完毕之后使用:
node app.js
#使用nodemon
nodemon app.js
只要是通过 nodemon
启动的服务,则他会监视你的文件变化,当文件发生变化的时候,会自动帮你重启服务器。
封装异步API
回调函数:获取异步操作的结果
function fn(callback){
// var callback = funtion(data){ console.log(data); }
setTimeout(function(){
var data = 'hello';
callback(data);
},1000);
}
// 如果需要获取一个函数中异步操作的结果,则必须通过回调函数的方式来获取
fn(function(data){
console.log(data);
})
数组常用的遍历方法
- forEach
- find
- findIndex
- every
- some
- includes
- indexOf
- map
- reduce
加密密码
MD5
安装
cnpm i blueimp-md5 --save
var md5 = require('blueimp-md5')
// 重复加密安全性更高
body.password = md5(md5(body.password))
规范
当一行代码是以:
(
[
`
开头的时候,则在前面补上一个分号以避免一些语法解析错误
在控制台使用 node
可以用来调试代码(API)
项目案例
目录结构
.
app.js 项目的入口文件
controllers
models 存储使用 mongoose 设计的数据模型
node_modules 第三方包
package.json 包描述文件
package-lock.json 第三方包版本锁定文件(npm5之后才有)
public 公共静态资源
README.md 项目说明文档
routes
routes.js
views 存储视图目录
模板页
路由设计
路径 | 方法 | get参数 | post参数 | 是否需要登录 | 备注 |
---|---|---|---|---|---|
/ | GET | 渲染首页 | |||
/register | GET | 渲染注册页 | |||
/register | email、nickname、password | 处理注册请求 | |||
/login | GET | 渲染登录页面 | |||
/login | POST | Email、password | 处理登录请求 | ||
/loginout | GET | 处理退出请求 |
模型设计
功能实现
步骤
- 创建目录结构
- 整合静态页-模板页
- include
- block
- extend
- 设计用户登陆,退出,注册的路由
- 用户注册
- 先处理客户端页面的内容(表单控件的 name,收集表单数据,发起请求)
- 服务端
- 获取从客户端表单请求数据
- 操作数据库
- 如果有错,发送 500 告诉客户端服务器错了
- 其他的根据业务发送不同的响应数据
- 用户登录
- 用户退出
Express中间件
中间件的概念
中间件的本质就是一个请求处理方法,我们把用户从请求到响应的整个过程分发到多个中间件中去处理,这样做的目的是提高代码的灵活性,动态可扩展的
把数据从请求到响应分步骤来处理,每一个步骤都是一个中间处理环节。
var http = require('http');
var url = require('url');
// 模拟第三方包(中间件)
var cookie = require('./ middleware /cookie');
var query = require('./ middl e wa re/query');
var postBody = require('./ middl e wa re/post-body');
var server = http.createServer(function(){
// 解析请求地址中的get参数
// var obj = url.parse(req.url,true);
// req.query = obj.query;
query(req,res); //中间件
// 解析请求地址中的post参数
req.body = {
foo:'bar'
}
});
if(req.url === 'xxx'){
// 处理请求
...
}
server.listen(3000,function(){
console.log('3000 runing...');
});
同一个请求对象所经过的中间件都是同一个请求对象和响应对象。
var express = require('express');
var app = express();
app.get('/abc',function(req,res,next){
// 同一个请求的req和res是一样的,
// 可以前面存储下面调用
console.log('/abc');
// req.foo = 'bar';
req.body = {
name:'xiaoxiao',
age:18
}
next();
});
app.get('/abc',function(req,res,next){
// console.log(req.foo);
console.log(req.body);
console.log('/abc');
});
app.listen(3000, function() {
console.log('app is running at port 3000.');
});
中间件的分类
应用程序级别的中间件
万能匹配(不关心任何请求路径和请求方法的中间件):
app.use(function(req,res,next){
console.log('Time',Date.now());
next();
});
关心请求路径和请求方法的中间件:
app.use('/a',function(req,res,next){
console.log('Time',Date.now());
next();
});
路由级别中间件
严格匹配请求路径和请求方法的中间件
get:
app.get('/',function(req,res){
res.send(' H e llo World! ');
});
post:
app.post('/a',function(req,res){
res.send('Got a POST request');
});
put:
app.put('/user',function(req,res){
res.send(' Got a PUT request at /user ');
});
delete:
app.delete('/delete',function(req,res){
res.send(' Got a DELETE request at /user ');
});
执行顺序
var express = require('express');
var app = express();
// 中间件:处理请求,本质就是个函数
// 在express中,对中间件有几种分类
// 1. 不关心任何请求路径和请求方法的中间件
// 也就是说任何请求都会进入这个中间件
// 中间件本身是一个方法,该方法接收三个参数
// Request 请求对象
// Response 响应对象
// next 下一个中间件
// // 全局匹配中间件
app.use(function (req, res, next) {
console.log('1');
// 当一个请求进入中间件后,如果不调用 next 则会停留在当前中间件
// 如果需要请求另外一个中间件则需要使用 next()方法
// next是一个方法,用来调用下一个中间件
// 注意:next() 方法调用下一个方法的时候,也需要匹配(不一定是调用紧挨着的哪一个)
next();
});
app.use(function (req, res, next) {
console.log('2');
});
// 2 关心请求路径的中间件
// 以 /xxx 开头的中间件
// 执行顺序为符合第一个参数的条件
app.use('/a', function (req, res, next) {
console.log(req.url);
});
// 3. 严格匹配请求方法和请求路径的中间件
// 请求路径必须是 / 而不是 / 开头
app.get('/', function (req, res, next) {
console.log('/');
});
app.post('/a', function (req, res, next) {
console.log('/a');
});
app.listen(3000, function () {
console.log('app is running at port 3000.');
});
错误处理中间件
app.use(function(err,req,res,next){
console.error(err,stack);
res.status(500).send('Something broke');
});
配置使用404中间件:
// 放在最后
app.use(function(req, res){
res.render('404.html');
});
配置全局错误(500)处理中间件:
app.get('/a', function(req, res, next) {
fs.readFile('.a/bc', funtion() {
if (err) {
// 当调用 next() 传参后,则直接进入到全局错误处理中间件方法中
// 当发生全局错误的时候,我们可以调用next传递错误对象
// 然后被全局错误处理中间件匹配到并进行处理
next(err);
}
})
});
//全局错误处理中间件
app.use(function(err,req,res,next){
res.status(500).json({
err_code:500,
message:err.message
});
});
内置中间件
- express.staticserves static assets such as HTML files, images, and so on.
- express.jsonparses incoming requests with JSON payloads. NOTE: Available with Express 4.16.0+
- express.urlencodedparses incoming requests with URL-encoded payloads. NOTE: Available with Express 4.16.0+
- express.urlencoded
第三方中间件
报错
npm 安装报错
- npm ERR! Refusing to install package with name “xxxx” under a packagexxxx
解决方法 :
检查package.json下的name字段是不是项目名字和你安装的那个包名字相同了,如果一样就会报错,把项目名字改成和你安装不冲突的名字。
Mongodb 报错
- (node:6608) DeprecationWarning: current URL string parser is deprecated, and will be removed in a future version. To use the new parser, pass option { useNewUrlParser: true } to MongoClient.connect.
(Use node --trace-deprecation ...
to show where the warning was created)
(node:6608) DeprecationWarning: current Server Discovery and Monitoring engine is deprecated, and will be removed in a future version. To use the new Server Discover and Monitoring engine, pass option { useUnifiedTopology: true } to the MongoClient constructor.ion. To use the new Server Discover and Monitoring engine, pass option { useUnifiedTopology: true } to the MongoClient constructor.
解决方法 :
虽然保存成功了但是 current URL string parser is deprecated, and will be removed in a future version.
在 mongoose.connect(‘mongodb://localhost:27017/itcast’); 中添加 { useNewUrlParser: true, useUnifiedTopology: true }
mongoose.connect('mongodb://localhost:27017/itcast', { useNewUrlParser: true, useUnifiedTopology: true });