Node
概述
Node是一个基于Chrome V8引擎的JavaScript代码运行环境。
安装
下载
官方网址:https://nodejs.org/en/
LTS:Long Term Support 长期支持版(稳定版)。
Current:拥有最新特性版本(实验版)。
验证
在windows PowerShell(超级管理员命令行)输入node -v
,如果有版本返回那么就安装完毕。没有则失败。
组成
node.js是由ECMAScript及Node环境提供的一些附加API组成的。
执行
在命令行执行,使用node 文件名称(包含尾缀)
命令执行js文件。
按住Shift + 鼠标右键 可快速打开管理员命令行。
Ctrl + c键终止程序。
windows PowerShell小技巧:
- 键盘↑键可以快速输入上次输入的命名。
- Tab键快速补充。
- clear 清屏。
同步API和异步API
概述
同步API:只有当前API执行完毕后,才能继续执行下一个API。
异步API:当前API的执行不会阻塞其他API执行。
区别
-
同步API可以通过返回值拿到API执行结果,但是异步API不行。–返回值
-
同步API是从上向下的执行,前面代码会堵塞后面的代码的执行。–执行顺序
异步API不会等待API执行完成后再向下执行代码。
Node.js全局对象global
在游览器中全局对对象是window,在Node中全局对象是global。
Node中全局对象可以使用以下方法,可以在任意位置使用,global可以省略。
- console.log() 在控制台打印输出
- setTimeout() 设置定时器
- clearTimeout() 清除定时器
- setInterval() 设置间歇定时器
- clearInterval() 清除间歇定时器
异步任务解决方案
Promise
概述
Promise的目的是解决Node.js异步编程中回调地狱的问题,分离结果和错误。降低代码的维护难度。
回调地狱:在异步任务嵌套异步任务,嵌套层数过多。
使用
let 变量名(promise) = new Promise(function(resolve,reject) {
resolve:是一个函数,当异步任务有结果时,当做参数传递出去(当做了promise中方法回调函数的参数,再传递给我们使用)。
reject:是一个函数,当异步任务执行失败,可以通过参数传递出去。
});
在外面使用异步任务结果:
异步任务执行成功时:
promise.then(function(result) {
});
异步任务执行失败时:
promise.catch(function(result) {
});
使用链式编程时:
promise.then(function(result) {//成功时
//可以使用return返回值,返回的值就是下个.then()方法的被执行对象。(这样就可以实现链式编程)
}).catch(function(err) {//失败时
});
示例
const fs = require('fs');//引入fs模块
let pormise = new Promise(function (resolve,reject){//创建Promise对象
fs.readFile('路径地址path','字符集utf8',function(err,result) {//创建读取文件的异步任务
if (err != null) {//判断读取是否成功:失败,就是用reject函数以参数的形式传递出去
reject(err);
}else {//如果成功,那么就使用resolve函数以参数的形式传递出去
resolve(result);
}
});
});
pormise.then(function(result) {//成功时,处理函数
}).catch(function(err) {//失败时,处理函数
});
异步函数
概述
异步函数时异步编程的终极奥义解决方案,它的作用是将我们的异步代码书写成同步的形式,使其代码更易阅读,降低代码维护难度。
语法
//1.在普通函数之前添加 async 关键字将其转换为异步函数。
//2.异步函数默认的返回值就是Promis对象。
修饰符 变量名 = async function() {
};
async function 函数名称() {
return 返回值;//这个返回值可以使用.then方法进行使用、
throw 抛出错误信息;//使用throw关键字,可以抛出错误信息。使用catch方法使用该抛出打错误信息。
}
注意:
1.如果有函数有返回值,它的返回值是基于Promis对象。返回值为Promis的属性或者方法。
使用
async function fn() {
return 'fn';//这个返回值可以使用.then方法进行使用、
throw '这是fn的错误信息';//使用throw关键字,可以抛出错误信息。使用catch方法使用该抛出打错误信息。
}
async function fn2() {
return 'fn2';//这个返回值可以使用.then方法进行使用、
throw '这是fn2的错误信息';//使用throw关键字,可以抛出错误信息。使用catch方法使用该抛出打错误信息。
}
async function fn3() {
return 'fn3';//这个返回值可以使用.then方法进行使用、
throw '这是fn3的错误信息';//使用throw关键字,可以抛出错误信息。使用catch方法使用该抛出打错误信息。
}
async function run() {//使用async关键字,将普通函数声明称异步函数
await fn()//使用await关键字,可以堵塞代码,就是fn()函数没有执行结果返回就不往下执行了。这样就可以达到一一读取的效果。
await fn2();
await fn3();
}
注意
- async:使用此关键字可以将普通函数转化为异步函数。
- 异步函数的返回值默认为Promis对象。
- 在异步函数内部可以使用return关键字进行结果返回,结果会被包含在Promis对象中。
- 在异步函数内容可以使用throw关键字抛出错误信息。
- 在异步函数外面可以通过Promis对象中then方法使用异步函数的返回值。
- 在异步函数外面可以通过Promis对象中的catch方法获取异步函数的错误信息。
- await:【只能在异步函数中使用,后面必须跟Promis对象】使用该关键字可以堵塞异步函数的执行,只有当前函数有返回值结果才可以往下执行。
在Node.js中解决fs.readFild异步函数的方法
在Node.js中提供了可以将fs.readFild方法返回值转换为Promis对象的方法。这个方法就是-util内置模块下的promisify对象。
const fs = require('fs');//引用fs模块
const promisify = require('util').promisify;//获取promisify对象
const readFile = promisify(fs.readFile);//使用promisify对象将fs.readFile方法的返回值转换为Promis对象
async function() {
let 变量名 = await readFild('路径地址path','字符集utf8');
}
Node.js模块化开发
JavaScript开发弊端
JavaScript开发弊端时,存在两大问题:文件依赖和命名冲突。
Node.js中模块化开发规范
node.js规定一个JavaScript文件就是一个模块,模块内部定义的变量和函数默认情况下在外部无法访问。
模块内部可以使用exports对象进行成员导出,使用requier方法导入其他模块。
导出
exports.属性名 = 被导出对象;
导入
修饰符 变量名 = require(路径地址);//导入路径地址可以省略后缀(.js)。
属性导出的另一种方法:
module.exports.属性名 = 被导出对象;
注意:exports是module.exports的别名(地址引用关系),导出对象最终以module.exports为准。
系统模块
系统模块:就是Node运行环境提供的API,因为这些API是模块化开发的,所以我们也称为Node运行环境提供API为系统环境。
系统模块fs文件操作
f:File文件,s:System系统,文件操作系统。
使用前需要引用fs模块。
读取文件内容
fs.readFile('文件路径地址',[文件编码],回调函数callback);
fs.readFile('文件路径地址',[文件编码],function(错误err【读取信息,无错误为null】,对象doc【文件读取结果】) {
});
写入文件内容
fs.writeFile('文件路径地址','写入内容',回调函数callback);
fs.writeFile('文件路径地址','写入内容',function(错误err【读取信息,无错误为null】) {
//如果文件不存在,那么writeFild方法会帮你创建一个新文件。
});
系统模块path路径操作
路径拼接语法
path.join('路径','路径',...);//将传参路径地址拼接,返回值为拼接结果(字符串)。
相对路径or绝对路径
相对路径:相对于**执行工具(命令行)**出发的路径。
绝对路径:以盘符为原点出发的路径。
使用**_ _dirname**获取当前目录的绝对路径。
在html文件中会外联许多文件,比如:
css/base.css
改成绝对路径:
/css/base.css
绝对路径是直接输入在浏览器的,不会和之前的文件拼接。而相对路径,如果访问的网页已经在文件夹中,那么它会拼接之前的文件夹。
URL模块
功能:URL模块可以解析请求对象的url地址。
const http = require('http');//引用http模块
const url = require('url');//引用url模块
const app = http.createServer();//创建服务器
app.on('request',function(请求对象,响应对象) {//添加响应事件
let url = url.parse(请求对象.url,布尔值(是否将返回值以对象形式返回));
url对象属性:
pathname:请求地址
query:?之后的参数信息
});
app.listen(端口号);//监控端口
第三方模块
第三方模块是别人写好的、具有特定功能的,我们可以直接使用的模块。第三方模块也是包。
第三方模块存在的两种形式:
- 以js文件的形式存在,提供实现项目具体功能的API接口。
- 以命令行工具形式存在,辅助开发工具。
npm(node package manager):是node的第三方模块管理工具。
在windows PowerShell下输入
npm install 模块名称;//下载第三方模块(默认下载到命令行当前目录)。可以同时下载多模块,用空格相隔。
npm uninstall package 模块名称;//删除第三方模块。
nodemon
nodemon是一个命令行工具,可以辅助项目开发。
在Node.js中,每次修改文件都要在命令行中重新执行该文件,非常繁琐。
使用步骤
1.使用npm install nodemon -g//下载nodemon,-g全局安装。
2.ctrl + c//停止监听
nrm
nrm(npm registry manager):npm下载路径切换工具。
使用环境:国内访问官方网站速度较慢,可以使用一些国内搭建的网站代替。
使用步骤
1.使用npm install nrm -g//下载nrm,-g全局安装。
2.查询可使用下载地址列表nrm ls
3.切换npm下载地址nrm use 下载地址名称
Gulp
基于node平台开发的前端构建工具。
将机械化操作编写成任务,想要执行机械化操作时只需执行一个命令即可。提高了开发效率。
功能:
- 项目上线前,HTML、CSS、JS文件压缩合并。
- 语法转换(es6、less…)。
- 公共文件抽取。
- 修改文件游览器自动刷新。
使用步骤
1.使用npm install gulp//下载gulp库文件
2.在项目根目录下,创建gulpfile.js文件。
3.重构项目的文件夹结构,src目录放置源代码文件 dist目录放置构建后的文件。
4.在gulpfile.js文件中编写任。
(1)引入gulp模块
(2)使用gulp模块,编写任务。
5.在命令行工具中执行gulp任务。
(1)在命令行通过npm install gulp-cli -g//安装gulp命令行工具(-g全局安装)
(2)安装后。执行gulp 任务名称//执行任务
执行过程出现的常见错误:
[23:46:01] The following tasks did not complete: test
[23:46:01] Did you forget to signal async completion?
解决方案:
给使用task创建任务的参数列表中回调函数,添加参数,并且回调一下即可。
gulp.task('任务名称',function(参数名) {
参数名();//最后调用
});
方法
1.gulp.scr():获取文件
gulp.scr('路径地址');
2.gulp.dest():输出文件
注意:gulp.dest()方法必须写在任务.pipe()的括号中。
3.gulp.task():建立gulp任务
gulp.task('任务名称',回调函数);
gulp.task('任务名称',function() {
});
gulp.task('default',['任务列表']);//当执行这个任务时,任务列表中的任务也会被执行。这个任务称为“构建任务”。【旧】
新版本:使用paralle或者使用series把任务包括起来。
4.gulp.watch():监控文件变化
插件
gulp-htmlmin:html文件压缩
gulp-csso:压缩css文件
gulp-babel:javascript语法转换
gulp-less:less语法转换
gulp-uglify:压缩混洗javascript
gulp-file-include:公共文件包含
browsersync:浏览器实时同步
使用插件步骤:
1.使用npm工具下。
2.创建任务时引用模块。
注意:主要根据API进行操作。
gulp-file-include公共文件包含的简单使用步骤:
1.使用npm工具下:npm install --save-dev gulp-file-include。
2.创建任务时引用模块:const fileinclude = require('gulp-file-include');。
3.需要引入公共部分的html文件中书写:@@include('公共代码路径地址')。
Package.json文件的说明
项目描述文件,记录了当前项目信息。例如:项目名称、版本、作者、gulpub地址。当前项目依赖第三方模块。
- 使用npm init -y命令生成(-y是使用默认配值)。
package.json文件内容:
{
"name": "description",//项目名称
"version": "1.0.0",//版本号
"description": "",//项目描述
"main": "index.js",//项目主入口文件
"scripts": {//命令别名
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],//关键字
"author": "",//项目作者
"license": "ISC"//项目协议
"dependencies":{//项目依赖模块
}
"devDependencies":{//开发依赖模块
}
}
使用npm install,不加任何模块名,它会去找package.js文件,自动下载所有依赖模块。
npm install--production//下载 项目依赖 模块
scripts别名的使用:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
//"别名":"命令"
},
在命令行输入npm run 别名,就可以执行别名中的命令了。
使用环境:命令较长时,起别名更加高效。
项目依赖
在项目的开发阶段和上线运营阶段,都需要依赖的第三方包,称为项目依赖。
可以通过npm install命令下载的文件会默认被添加到package.json项目说明文件中。
开发依赖
在项目开发中使用的模块,但是上线运营不需要。
使用npm install 包名 --save-dev 命令将不会添加到package.json文件中。
package-lock.json文件作用
- 锁定包的版本,确定再次下载不会因为版本不同而产生问题。
- 加速下载速度,因为该文件已经记录了项目模块依赖关系和下载地址,所有再次下载不用再次解析模块依赖关系和下载地址。
mime模块
mime模块可以帮助我们判断读取文件的类型。
使用步骤
1.下载模块:npm install mime
2.在js文件中引入模块:const mime = require('mime');
3.使用模块中的getType('路径地址path')方法判断读取文件的类型,返回值就是类型。
router模块
主要功能实现路由,简化代码。
使用步骤
- 获取路由对象
- 调用路由对象提供的API方法创建路由
- 启动路由,使其生效。
代码展示
1.获取路由对象
const getRouter = require('router');//引用模块。
const router = getRouter();//调用getRouter方法获取router路由对象。
2.获取路由对象提供的方法创建路由
router.get('路径path',(request,response) => {//创建get路由处理函数。
response.end('');
});
3.启动路由,使其生效
server.on('request',(request,response) => {//服务器每次接受请求,就会调用一次路由。
router(request,response,() => {});//第三个参数回调函数,必填参数。
});
模板引擎
模板引擎第第三方模块,
让开发者一更加友好的方式拼接字符串,是项目更加清晰、更易维护。
art-template模板引擎
1.在命令行工具中使用:npm install art-template
2.在代码中引入该模块:const template = require('art-tmplate');
3.在代码中将模板与特定数据进行拼接:const 变量名 = template('模板路径地址path', 拼接对象);
(1)返回值为拼接完成的字符串
模板语法
art-template同时支持两种模板语法:标准语法和原始语法。
标准语法可以让模板更容易读取,原始语法具有强大的逻辑处理能力。
输出
将某项数据输出在模板中。
标准语法:{{数据}}
原始语法:<%=数据 %>
注意:语法中还可以进行简单的运算。比如:加减乘除、三目运算符。
原文输出
如果数据中携带HTML标签,默认模板引擎不会解析标签,会将标签转义后输出。
标准语法:{{@数据}}
原始语法:<%-数据%>
条件判断
在模板中可以根据条件判断显示那块html代码。
标准语法:
单条件:{{if条件}}...{{/if}}
多条件:{{if条件}}...{{else if 条件2}}...{{/if}}
示例:
<div>
<span>{{if age>18}}年龄大于18时显示{{else if age<18}}年龄小于14时显示{{/if}}</span>
</div>
原生语法:
单条件:<% if (value判断条件) {%>...<%}%>
多条件:<% if () {%> <%} else if () {%> <%}%>
循环
标准语法:{{ecah 数据}}{{each}}
原始语法:<% for() {%> <%}%>
标准语法:
{{each 对象【数组】}}
{{$index}}//索引
{{$value}}//值
{{/each}}
原始语法:
<% for (let i = 0; i < 数组.length; i++);{%>
<%=i%>
<%数组[i]%>
<%}
=%>
子模板
使用头部模板将网站公共区域(头部、底部)抽离到单独的文件。
标准语法:{{include 模板路径}}
原始语法:<%include(‘模板路径’)%>
模板继承
使用模板继承可是将网站HTML骨架抽离到单独的文件中,其他页面模板可以继承骨架文件。
预留位置
{{block '名称'}} {{/block}}
继承模板
{{extend '骨架文件位置'}}
填充预留位置
{{block '名称'}}填充内容{{/block}}
模板配置
- 向模板中导入变量 template.defaults.imports.变量名 = 变量;
- 设置模板根目录 template.defaults.root = ‘根目录路径’;设置完根目录之后template(‘文件名称’, 拼接对象),不用书写路径,因为设置默认模板根目录之后,模板引擎会自动去找根目录下找文件。
- 设置模板文件默认后缀名 template.defaults.extname = ’后缀名‘;设置之后template(‘文件名称’, 拼接对象),就不用写文件名称的后缀了。
serve-static模块
功能:实现静态资源访问服务。
使用步骤
- 引入server-static模块获取创建静态资源服务功能的方法。
- 调用方法创建静态资源的方法并指定静态资源服务目录
- 启用静态资源服务功能
代码展示
const http = require('http'); //引入http模块
const path = require('path'); //引入path模板
const servestatic = require('serve-static'); //引入serverstatic模块
const static = servestatic(path.join(__dirname, 'public')); //通过serverstatic方法(并指定静态资源目录),获取返回值static对象
app.on('request', (request, response) => {
static(request, response, () => {}); //调用static方法,启动资源访问服务功能
});
app.listen(80);//监控端口
dateformat模块
主要功能:将Date对象时间格式转换成指定时间格式。
模块执行机制
模块查找规则-没有后缀时
-
require方法更具模块路径查找模块,如果是完整的路径,直接引入。
-
如果路径模块名后面没有后缀,先查找同名js文件在查找同名js文件夹。
-
如果找到同名文件夹,就会去找index.js
-
如果文件夹中没有index.js就会去当前文佳夹中的package.js文件中查找mian属性(文件主入口)
-
没有指定路口文件或者指定路径不对,那么就报错。
模块查找规则-当模块没有路径和后缀时
-
nods.js会假设它是系统文佳
-
node.js会去node_modules文佳夹中
-
首先查找有没有同名js文件
-
如果没有js文件,那么就去找同名文件夹
-
如果文件夹中没有index.js就会去文佳夹中的package.js文件中查找mian属性(文件主入口),找到执行
-
没有指定路口文件或者指定路径不对,那么就报错。
Express框架
Express框架是基于Node平台的Web应用开发架构,它提供了一系列强大特性,帮助你创建各种Web应用。
Express框架特性
-
提供了方便简洁的路由定义方式。(route模块就是从Express框架提取出去的)
-
对获取HTTP请求参数进行了简化处理
-
对模板引擎支持程度高,方便渲染动态HTML页面
-
提供了中间件机制有效控制HTTP请求
-
拥有大量第三方中间件对功能进行扩展
基本使用
const express = require('express'); //引入express框架模块
const app = express(); //创建服务器,并返回服务器对象
app.get('/', (request, respone) => { //创建路由
respone.send('Hello,Express'); //响应客户端
});
app.listen(80); //监控端口
使用send方法好处:
1.send方法会自动检测响应内容的类型
2.send方法会自动设置http状态码
3.send方法会帮我们自动设置响应的内型类型及编码
respone的方法:
res.status(状态码);
改变响应客户端头部信心中的状态码
中间件
中间件就是一堆方法,可以接收客户端的请求,可以对请求做出相应,也可以将请求继续交给下一个中间件继续处理。
中间件的组成
中间件的组成由两部分构成,中间件方法以及请求处理函数。
中间件方法由Express提供,负责拦截请求,请求处理函数由开发人员提供,负责处理请求。
Express框架下:
服务器对象.get('请求路径',(request, respone) => {});//接收get请求
服务器对象.post('请求路径',(request, respone) => {});//接收post请求
服务器对象.use('请求路径',(request, respone,[next]) => {});//不区分get或者post请求(不区分请求类型)
注意:
use方法如果没有书写请求路径形参,不管什么路径都会执行这个use方法中的处理函数。
注意事项
- 可以针对一个请求设置多个中间件(请求地址相同),对同一个请求进行多次处理。
- 默认情况下,请求从上自下依次匹配中间件,一旦匹配成功,终止匹配。
- 可以条用next()方法将请求的控制权交个下一个中间件,知道遇到结束请求的中间件。
服务器对象.get('请求路径',(request, respone,next) => {});//接收get请求,执行代码后,跳转至下一个中间件。
服务器对象.post(('请求路径',(request, respone,next) => {}) => {});//接收post请求,执行代码后,跳转至下一个中间件。
错误处理中间件
在程序执行的过程中,不可避免的会出现一些无法预料的错误,比如文件读取不存在、数据库链接失败。
错误处理中间件是一个集中处理错误的地方。
服务器对象.use('请求路径',(错误信息对象error,request, respone,next) => {});//接收get请求,执行代码后,跳转至下一个中间件。
注意事项:
错误处理中间件无法捕获异步错误信息,需要在书写异步代码时,将错误信息通过next()方法传递给错误处理中间件。
Error
Express框架内置的错误对象
throw new Error('错误信息');
捕获错误
在node.js中,异步API的错误信息都可以通过回调函数获取的,支持Promise对象的异步API发生错误可以通过catch方法捕获。
使用
//包装想要使用try{}catch(error){}捕获异常的方法
const express = require('express'); //引入express框架模块
const fs = require('fs'); //引入fs文件读写模块
const promisify = require('util').promisify; //导入util模块中的promisify方法
const readFild = promisify(fs.readFild);//使用promisify方法promisify方法包装
//异步方法,需要将其转为同步形式(async await)
app.get('/index', async(request, respone, next) => { //添加路由
try {//try包裹着未异常时执行代码
let data = await readFile('./01.js');
respone.send(data + '');
} catch (error) {//catch包裹着执行出现异常时该执行的代码,尝试继续执行程序,不让程序因错误停止
next(error);
}
});
模块化路由
构建模块化路由,有利于后续维护代码。
//引入模块
const express = require('express');
//创建服务器,并获取服务器对象
const app = express();
//获取router对象
const host = express.Router();
//创建一级路由,凡是/host地址的都调用host对象中的路由
app.use('/host', host);
//创建二级路由,/host/index路由处理
host.get('/index', (request, response) => {
response.status(200).send('欢迎来到首页!');//响应内容
});
//监听端口
app.listen(80);
//打印提示文字
console.log('服务器启动完成');
get参数
Express框架中使用request.query即可获取get参数,框架内部会将get参数转换为对象返回。
app.get('/index', (request, response) => {
//request.query获取get参数
let data = request.query;
console.log(data);
response.send('OK');
});
post参数
Express中接收post请求参数需要借助第三方body-parser。
//引入模块
const express = require('express');
const bodyParser = require('body-parser');
//创建服务器,并且获取服务器对象
const app = express();
//拦截所有请求,通过bodyParser模块对象下的urlencoded方法解析post参数
app.use(bodyParser.urlencoded({ extended: false }));//extended: false代表是否不使用Node系统内置的querystring对象解析post参数,true则是使用第三方模块qs,false则使用querystring
app.post('/add', (request, response) => {
console.log(request.body);//经过拦截所有请求,解析post参数后,request形参就多了一个body属性,这个body属性就是post参数对象的形式
});
//监控端口
app.listen(80);
//打印提示文字
console.log('服务器启动成功');
注意事项:
bodyParser.urlencoded({ extended: false })的返回值是一个函数,这样就相当app.use()方法中传递了一个函数。
Express路由参数
//引入模块
const express = require('express');
//创建服务器,并且获取服务器对象
const app = express();
//添加路由,/index/:id中的:id表示希望客户端传递以地址形式传递一个id参数
app.get('/index/:id', (request, response) => {
//request.params Express框架中提供获取路径参数的方法,返回值是对象形式的
response.send(request.params);
});
//监控端口
app.listen(80);
//打印提示文字
console.log('服务器启动成功');
注意事项:
这样做的优点是优化路径,提升美观。
示例:'/index/:id/:name/:age',
客户端地址:'http://loaclhost:80/index/12345678/zhangsan/18',
服务器获取参数:'{id:12345678,name:zhangsan,age:18}'。
静态资源访问
通过Express内置的express.static可以方便地托管静态文件。例如img、CSS、javascript文件等…
//引入模块
const express = require('express');
const path = require('path');
//创建服务器,并且获取服务器对象
const app = express();
//拦截所有请求,调用express对象下static方法托管静态资源
//express.static('路径地址')
app.use(express.static(path.join(__dirname, 'public')));
//监控端口
app.listen(80);
//打印提示文字
console.log('服务器启动成功');
注意:
上述拦截了所有请求,进行判断是否为静态资源,在进行访问资源。但也不必拦截所有请求,也可以指定特定路径。
模板引擎
为了使art-template模板引擎能够更好的和Express框架配合,模板引擎官方在原art-template模板引擎的基础上分装了express-art-template。
使用命令:npm install art-template express-art-template
//引入模块
const express = require('express');
const path = require('path');
//创建服务器,并获取服务器对象
const app = express();
//指定后缀为.art的使用express-art-template模板渲染
//app.engine('后缀名称', 指定模板);
app.engine('art', require('express-art-template'));
//指定模板文件夹
//app.set('views', 模板文件夹地址);,views是模板配置属性名(固定)
app.set('views', path.join(__dirname, 'views'));
//设置模板文件默认后缀名
//app.set('view engine', '后缀名');
app.set('view engine', 'art');
//创建路由
app.get('/', (request, response) => {
//响应拼接后的模板文件
// response.render('模板名称', {需要拼接的模板数据对象});
response.render('index', {
msg: 'message'
});
});
//错误处理
app.use((error, request, response, next) => {
response.status(500).send(error);
next();
});
//监听端口
app.listen(80);
//打印提示文字
console.log('服务器启动成功');
服务器对象.locals
将变量设置到app.locals对象下面这个数据在所有模板下都可以获取。
app.locals.属性名称 = {};//在app.locals对象下添加属性
URL
统一资源定位符,是Interent网上资源位置而设定的编址方式。
本机域名:localhost
本地IP:127.0.0.1
URL组成
传输协议://服务器IP或者域名:端口/资源所在位置标识符
服务器
Node网站服务器概念
能够提供网站访问服务的机器就是网站服务器,它能够接受客户端的请求,并作出相对应的响应。
Node.js创建Web服务器
一、创建网站js代码
// 一、引入http模块,http用于创建Web服务器的模块
const http = require('http');
// 二、createServer创建Web服务器,返回值为Web服务器对象
const app = http.createServer();
// 三、给Web服务器对象添加(反应)事件,request客户端请求时,调用该处理函数。
app.on('request', (request, response) => {
response.end('<h2>hi!</h2>');
});
/*
app.on(事件名称,处理函数);
app.on(事件名称,function(请求对象,响应对象) {
});
*/
// 四、监听端口
app.listen(3000);
/*
app.listen(端口号);//监听指定端口
*/
console.log('网站服务器启动成功!');//文件启动时的提示
二、执行js文件
在命令行输入:node js文件名称
三、测试
在本地输入网址:localhost:端口号,访问本地服务器。
HTTP协议
概述
HTPP(超文本传输协议)规定了如何从网站服务器传输超文本到本地浏览器,它是基于客户端架构工作,是客户端(用户)和服务器(网站)请求和应答的标准。
报文
在HTTP请求和响应的过程中传输的数据块叫做报文,包括了传送的数据和一些附加信息,并且要遵守规定好的格式。
请求报文
请求方式:
- GET 请求数据
- POST 发送数据
html中表单报文方式(一般为POST提交数据)
<!--
method:表单提交方式->报文方式
1)POST:数据提交(发送)
2)GET:数据请求
action:表单数据的提交地址
-->
<form method="POST" action="http://localhost:3000">
<label for="">账号:</label><input type="text" name="ures"><br>
<label for="">密码:</label><input type="password" name="password" id=""><br>
<input type="submit" value="提交">
</form>
Node的HTTP模块
HTTP模块事件响应中请求对象
const http = require('http');//引用http模块
const app = http.createServer();//创建服务器
app.on('request',function(请求对象,响应对象) {//添加响应事件
let 变量名 = 请求对象[或者响应对象].method;//报文方式
let 变量名 = 请求对象[响应对象].url;//获取请求地址
let 变量名 = 请求对象[响应对象].headers;//获取请求报文
let 变量名 = 请求对象[响应对象].headers['属性名'];//获取请求报文中指定属性的值
});
app.listen(端口号);//监控端口
响应报文
HTTP状态码
- 200:请求成功
- 301:重定向
- 404:请求的资源没有被找到
- 500:服务器端错误
- 400:客户端请求有语法错误
const http = require('http');//引用http模块
const app = http.createServer();//创建服务器
app.on('request',function(请求对象,响应对象) {//添加响应事件
响应对象.writeHead(状态码);//修改状态码
});
app.listen(端口号);//监控端口
内容类型
- text/html
- text/css
- application/javascript
- image/jpeg
- application/json
const http = require('http');//引用http模块
const app = http.createServer();//创建服务器
app.on('request',function(请求对象,响应对象) {//添加响应事件
响应对象.writeHead(状态码,{
响应头部信息;//以对象形式书写
'content-type':'text/plain;charset=utf8'//text/plain纯文本,charset=utf8指定字符集(分号相隔)
})
});
app.listen(端口号);//监控端口
头部信息
Location:通过方法writeHead()修改头部改变URL位置(一般用于网页跳转)。
URL模块[GET]
功能:URL模块可以解析请求对象的url地址。
const http = require('http');//引用http模块
const url = require('url');//引用url模块
const app = http.createServer();//创建服务器
app.on('request',function(请求对象,响应对象) {//添加响应事件
let url = url.parse(请求对象.url,布尔值(是否将返回值以对象形式返回));
});
app.listen(端口号);//监控端口
POST
POST是通过事件的形式接收的。
data:当请求参数传递时触发data事件。
end:当请求数据传递完毕时触发end事件。
注意:由于POST数据一定一次接收完毕,所以才会有data事件和end事件。
示例
const http = require('http');//引用http模块
const url = require('url');//引用url模块
const app = http.createServer();//创建服务器
app.on('request',function(请求对象,响应对象) {//添加响应事件
请求对象.on('data(事件名称)',function(数据片段(拼接在一起即可使用)) {//当数据(参数)传输时,触发
});
请求对象.on('end',function() {//当数据(参数)传输完毕时,触发
处理过程;
});
});
app.listen(端口号);//监控端口
querystring
通过以上步骤就可以获取用户发送过来的数据(参数),但是是一个字符串,需要处理。node.js中提供了querystring内置模块处理该字符串。
使用
let uesrData = querystring.parse(formData);
分析:
1.querystring.parse()将字符串解析成对象形式
2.将formData字符串解析成为对象形式,方便后续操作
示例
const http = require('http');//引用http模块
const url = require('url');//引用url模块
const querystring = require('querystring');//引入querystring模块
const app = http.createServer();//创建服务器
app.on('request',function(请求对象,响应对象) {//添加响应事件
let paramsPost = '';//创建储存POST数据包的变量
请求对象.on('data',function(params;) {//当数据(参数)传输时,触发
paramsPost += params;//拼接数据片段
});
请求对象.on('end',function() {//当数据(参数)传输完毕时,触发
var dataPost = querystring.parse(paramsPost);//解析数据包,将其转换成为对象形式,以便操作。
});
});
app.listen(端口号);//监控端口解析POST数据包
路由
概述
路由是指客户端请求地址与服务器程序代码之间的关系。简单来说就是客户端想要什么资源就给什么
资源即可。
资源
静态资源
服务器不需要处理,可以直接响应给客户端的资源就是静态资源。
动态资源
相同的请求地址不同的响应资源,这种资源就是动态资源。
MongoDB数据库
安装
百度自查
开始服务
net start moogodb//开启服务
net stop moogodb//关闭服务
数据类型
名词 | 说明 |
---|---|
Number | 数值型 |
String | 字符串 |
Date | 时间型 |
数据库相关概念
术语 | 说明 |
---|---|
database | 数据库,MongoDB数据库软件可以创建多个数据库 |
collectior | 集合,一组数据的集合,可以理解为JavaScript中的数组 |
document | 文档,一条具体的数据,可以理解为JavaScript中的对象 |
field | 字段,文档中的属性名称,可以理解为JavaScript中的对象属性 |
使用
node.js如果想使用MongoDB数据库需要下载第三方模块:MongoDB
连接数据库
1.在命令行中使用命令:
npm install mongoose
2.在js文件中引入mongoose模块:
const mongoose = require('mongoose');
3.创建数据库链接:
mongoose.connect('mongodb://链接地址url:端口/数据库名称', { useNewUrlParser: true, useUnifiedTopology: true })
//创建连接,连接数据库
//useNewUrlParser:使用新的URL解析器,useUnifiedTopology:使用使用统一的表学
.then(function() { //连接成功时:处理函数
console.log('数据库连接成功!');
})
.catch(function(错误信息error) { //连接失败时:处理函数
console.log('数据库连接失败!', error);
});
注意:
MongoDB数据库默认的端口为:27017
创建数据库
在MongoDB中不需要显示创建数据库,如果正在使用的数据库不存在,MongoDB会自动创建。
创建集合
创建集合分为两步,一是对集合设定规则,二是创建集合。
//(一)引入mongoose模块
const mongoose = require('mongoose');
//(二)连接数据库
mongoose.connect('mongodb://localhost/databaseName', { useNewUrlParser: true, useUnifiedTopology: true })
.then(function() { //连接成功时:处理函数
console.log('数据库连接成功!');
})
.catch(function(error) { //连接失败时:处理函数
console.log('数据库连接失败!', error);
});
//(三)创建集合
// 1.创建集合的规则(所有字段或者集合属性)
let schema = new mongoose.Schema({
//1.创建模式对象(集合规则),通过构造函数添加字段规则
//2.返回值模式对象(集合规则)对象
name: String,
author: String,
isCourseOpen: Boolean
//(字段名称:字段数据类型)
});
// 2.使用集合规则创建集合
let 构造函数名称 = mongoose.model('Course', schema);
//1.创建集合,实际上它在创建集合名时会添加s结尾,此案例为:courses
//2.model()创建集合之后,会返回一个集合的构造函数。
注意:
已经创建数据库和集合而没有数据时,数据库中不会显示。
创建文档
//(一)引入mongoose模块
const mongoose = require('mongoose');
//(二)连接数据库
mongoose.connect('mongodb://localhost/databaseName', { useNewUrlParser: true, useUnifiedTopology: true })
.then(function() {
console.log('数据库连接成功!');
})
.catch(function(error) {
console.log('数据库连接失败!', error);
});
//(三)创建集合
let schema = new mongoose.Schema({
name: String,
author: String,
isCourseOpen: Boolean
});
let Course = mongoose.model('Course', schema);
//(四)创建文档:方法一
let document = new Course({ //创建文档,构造函数中传递以对象的形式文档内容
name: '小美的上分之路',
author: '陈主任',
isCourseOpen: false
//(字段名称:字段值)
});
document.save(); //保存数据
//方法二
Course.create({字段数据内容}, 回调函数(错误信息,结果信息【以对象形式返回】));//create()方法返回的也是Promis对象
Course.create({//使用Course集合构造函数中的creat方法创建文档
name: '关于我是大帅逼的自我修养',
author: '黑人的乔丹鞋',
isCourseOpen: true
//构造函数中传递以对象的形式文档内容(字段名称:字段值)
}, function(error, result) {//回调函数(错误信息,结果信息【以对象形式返回】){}
console.log('错误信息:', error);
console.log('结果:', result);
});
mongoDB数据库导入数据
mongoimport -d 数据库名称 -c 集合名称 --file 要导入的数据文件
注意:
1.新版mongoDB数据库将这类型功能分离了出去,需要单独下载,解压到mongoDB根目录下[详细方法请百度]
2.执行该指令前需要在系统环境变量path中添加mongoDB根目录
查询数据(文档)
等于
//(一)find()
集合构造函数对象.find().then().catch();
//1.find()方法返回值是一个Promis对象,也就是说可以使用then()和catch()方法。
//2.find()方法的返回值结果是一个数组,查询的数据条数不会影响。
//3.find()方法如果没有参数传递的话,那么默认查询集合中所有文档
集合构造函数对象.find({
查询条件
//'字段名称':字段值
}).then().catch();
//(一)findOne()
集合构造函数对象.findOne().then().catch();
//1.返回值为对象
//2.当没有参数传递时,默认返回第一条文档数据。
小于、大于
集合构造函数对象.find(字段名:{$gt:值1,$lt:值2}).then().catch();
//字段名:条件(条件值为对象形式传递){
$gt:值1,
$lt:值2
//大于值1,小于值2
}
//$gt:大于
//$lt:小于(这是固定语法)
示例:
User.find({ 'age': { $gt: 18, $lt: 40 } }).then(res => console.log(res));//查询User集合中字段age大于18小于40的文档
包含
集合构造函数对象.find(字段名:{$in:['值']}).then().catch();
//$in包含某字符,条件值为数组形式传递
示例:
User.find({hobbies: { $in: ['敲代码'] }}).then(result => console.log(result));//查询User集合中字段名hobbies包含敲代码的文档。
查询字段
集合构造函数对象.find().select('字段名 -字段名').then().catch();
//1.字段名之间使用空格隔开
//2.不想显示的字段前加-,如:-_id不显示_id字段
排序
集合构造函数对象.find().sort('字段名').then().catch();
//1.sort()方法按照指定字段名排序,默认升序
//想要降序排名,在字段名前加-,如:-age按降序排列age字段
跳过、限制
集合构造函数对象.find().skip(值).limit(值).then().catch();
//skip()跳过指定条文档
//limit()限制指定条文档显示
删除文档
删除单个文档
集合构造函数对象.findOneAndDelete(条件(以对象形式传递).then().catch();
User.findOneAndDelete({'_id': '5c09f2d9aeb04b22f846096b'}).then(res => console.log(res));
//删除User集合中_id为5c09f2d9aeb04b22f846096b
删除多个文件
集合构造函数对象.deleteMany(条件(以对象形式传递)).then().catch();
//如果不传递参数或者传递空参数,它默认会删除集合中所有文档。
//deleteMany()方法返回一个对象,包含删除文档个数、执行状况等信息
更新文档(修改)
更新单个文档
集合构造函数对象.updateOne({查询条件},{修改条件}).then().catch();
//更新单条文档,如果同时多条文档瞒住,值修改查询到的第一条文档。
更新多个文档
集合构造函数对象.updateMany({查询条件}, {修改条件}).then().catch();
//查询条件为空,则是修改集合中所有文档
mongoose验证
在创建集合规则时,可以设置当前字段的验证规则,验证失败就不允许插入数据。
- required:true 必传字段(类似于MySql中的主键)
- minlength:数字型值【限定字符串最小长度】
- maxlength:数字型值【限制字符串最大长度】
- min:数值型使用,限制数字大小。
- max:数值型使用,限制数字大小。
字段值对象验证属性
属性 | 使用 | 说明 |
---|---|---|
type | 类型 | |
required | 必传字段 | |
minlength | 字符串最小长度限制 | |
maxlength | 字符串最大长度限度 | |
min | 数值型最小值限制 | |
max | 数值型最大型限制 | |
enum | {values:指定元素数组,message:‘错误信息’} | 枚举,只能是包含之中的元素才可以输入进指定字段 |
validate | validate:{validator:function(value) {函数体},message:‘错误信息’} | 检验,以对象形式添加规则,其中有个属性validetor(处理函数(值value))检验器,配合使用 |
unique | 唯一 |
在创建集合规则时,给字段添加验证
let 变量名 = mongoose.Schema({
//字段名:字段值
title:{
type:String,//说明这个字段是String类型数据
required:true //将required属性设置为true,说明该字段为必传字段
required:[true,'自定义错误信息']//属性值可以是数组类型,第二个元素为自定义错误信息
}
});
示例:
let articleSchema = mongoose.Schema({ //创建集合规则
title: {
type: String,
required: [true, '请输入文章标题'], //限制条件
minlength: [2, '您输入的标题不能低于2个字符!'],
maxlength: [5, '您输入的标题不能高于5个字符!'],
unique:true//保证数据唯一
}
age: {
type: Number,//数值型
min: 1,//最小值1
max: 100//最大值100
},
publicshDate: {
type: Date,//时间型
default: Date.now//Date.now获取当前时间,default默认值。
subject:{
type:String,//字符串类型
enum:['java','javascript','html','css']//枚举,存储的subject字段必须是其中之一。
},
author:{
type:String,//字符串类型
validate:{//检验
validator:value => {//检验器
return value && value.length > 4
},
message:'不满足自定义条件'//错误输出信息
}
}
});
let Article = mongoose.model('Article', articleSchema); //使用集合规则创建集合
Article.create({字段名:字段值})
.then(reslut => {
//打印正确时返回值
console.log(reslut);
})
.catch(error => {
//获取错误信息对象
const err = error.errors;
//for对象内容,打印出关键错误信息
for (var attr in err) {
console.log(err[attr]['message']);
}
}); //使用create()方法创建文档
打印错误信息
在增、删、改、查时打印主要的错误信息,可以使用.catch()方法参数error错误对象,获取其中的errors对象。遍历该对象,打印其中的message消息(这个消息一般就是我们自定义的错误信息了)。
集合关联
概述
通过不同集合的数据之间是有关系的。例如文章内容和用户信息存储在不同集合。但文章是某个用户发表的,要查询文章的所有信息包括发表用户,就需要关联。
使用
1.在集合限制条件下创建关联
type: mongoose.Schema.Types,//type类型:mongoose.Schema.Types(固定)
ref: 'user'//ref关联集合
2.使用关联
populate()方法查询关联字段
集合.find().populate('关联字段名').then(result => console.log(result)).catch();