Node.js

Node.js

Node.js的Http服务器

  • 引入required模块:我们可以使用require指令来载入Node.js模块。
  • **创建服务器:**服务器可以监听客户端的请求,类似于Apache 、Nginx等HTTP服务器。
  • 接收请求与响应请求:服务器很容易创建,客户端可以使用浏览器或终端发送HTTP请求,服务器接收请求后返回响应数据。

NPM

建立了NodeJS生态圈

包管理工具,新版nodejs已经集成了npm

升级:npm install npm -g

本地安装

  • \1. 将安装包放在 ./node_modules 下(运行 npm 命令时所在的目录,即当前项目目录),如果没有 node_modules 目录,会在当前执行 npm 命令的目录下生成 node_modules 目录。
  • \2. 可以通过 require() 来引入本地安装的包。

全局安装

  • \1. 将安装包放在 /usr/local 下或者你 node 的安装目录。
  • \2. 可以直接在命令行里使用。

如果你希望具备两者功能,则需要在两个地方安装它或使用 npm link。

NPM应用场景

  • 下载第三方包
  1. npm i 安装包名称 —默认下载最新版本
  2. npm i 安装包名称@ —下载指定版本的安装包
  3. NPM对package.json的字段做了扩展,允许在其中申明第三方包依赖(dependencies中用键值对的写法)
  • 安装命令行程序
  1. 从NPM服务上下载安装一个命令行程序的方法与第三方包类似。
  2. 例如上例中的node-echo提供了命令行使用方式,只要node-echo自己配置好了相关的package.json字段,对于用户而言,只需要使用以下命令安装程序。
  • 发布代码
  1. 第一次使用NPM发布代码前需要注册一个账号。终端下运行npm adduser,之后按照提示做即可。

版本号

使用NPM下载和发布代码时都会接触到版本号。NPM使用语义版本号来管理代码,这里简单介绍一下。

语义版本号分为X.Y.Z三位,分别代表主版本号、次版本号和补丁版本号。当代码变更时,版本号按以下原则更新。

  • 如果只是修复bug,需要更新Z位。
  • 如果是新增了功能,但是向下兼容,需要更新Y位。
  • 如果有大变动,向下不兼容,需要更新X位。

版本号有了这个保证后,在申明第三方包依赖时,除了可依赖于一个固定版本号外,还可依赖于某个范围的版本号。例如"argv": "0.0.x"表示依赖于0.0.x系列的最新版argv。

NPM支持的所有版本号范围指定方式可以查看官方文档。

NPM常用命令

除了本章介绍的部分外,NPM还提供了很多功能,package.json里也有很多其它有用的字段。

除了可以在npmjs.org/doc/查看官方文档外,这里再介绍一些NPM常用命令。

  • NPM提供了很多命令,例如install和publish,使用npm help可查看所有命令。
  • 使用npm help 可查看某条命令的详细帮助,例如npm help install。
  • 在package.json所在目录下使用npm install . -g可先在本地安装当前命令行程序,可用于发布前的本地测试。
  • 使用npm update 可以把当前目录下node_modules子目录里边的对应模块更新至最新版本。
  • 使用npm update -g可以把全局安装的对应命令行程序更新至最新版。
  • 使用npm cache clear可以清空NPM本地缓存,用于对付使用相同版本号发布新版本代码的人。
  • 使用npm unpublish @可以撤销发布自己发布过的某个版本代码。

Node.js REPL(交互式解释器)

Node.js REPL(Read Eval Print Loop:交互式解释器) 表示一个电脑的环境,类似 Window 系统的终端或 Unix/Linux shell,我们可以在终端中输入命令,并接收系统的响应。

REPL 的交互式的编程环境可以实时的验证你所编写的代码,非常适合于验证 Node.js 和 JavaScript 的相关 API。

REPL的作用

Node 自带了交互式解释器,可以执行以下任务:

  • 读取 - 读取用户输入,解析输入了Javascript 数据结构并存储在内存中。
  • 执行 - 执行输入的数据结构
  • 打印 - 输出结果
  • 循环 - 循环操作以上步骤直到用户两次按下 ctrl-c 按钮退出。

开始学习REPL

启动终端

在命令行中输入node回车,这时我们就可以在 > 后输入简单的表达式,并按下回车键来计算结果。

**简单表达式运算:**加减乘除运算

**使用变量:**var关键字声明变量,没有var会直接打印出来,使用var可以用console.log()来输出

**多行表达式:**类似js的语句

下划线变量:

$ node

var x = 10
undefined
var y = 20
undefined
x + y
30
var sum = _
undefined
console.log(sum)
30
undefined

REPL命令

  • ctrl + c - 退出当前终端。
  • ctrl + c 按下两次 - 退出 Node REPL。
  • ctrl + d - 退出 Node REPL.
  • 向上/向下 键 - 查看输入的历史命令
  • tab 键 - 列出当前命令
  • .help - 列出使用命令
  • .break - 退出多行表达式
  • .clear - 退出多行表达式
  • .save filename - 保存当前的 Node REPL 会话到指定文件
  • .load filename - 载入当前 Node REPL 会话的文件内容。

服务器端开发要做的事

  1. 实现网站的业务逻辑
  2. 数据增删改查

node概念

  • Node:基于Chrome V8引擎的JavaScript代码的运行环境
  • LTS:Long Term Support长期支持稳定版
  • Node.js
    • ECMAScript语法(JS核心语法)
    • node环境提供的API
  • node 文件名//执行文件
  • Shift+右键:在当前窗口打开PowerShell
  • 输入文件名开头+Tab可以自动补全
  • clear:清屏

Node的全局对象-global

  • console.log()
  • setTimeout()
  • clearTimeout()
  • setInterval()
  • clearInterval()

模块化开发

  1. Node.js规定一个js文件就是一个模块,模块内部定义的变量和函数默认在外部无法得到
  2. export对象进行成员(属性和方法)导出
  3. require方法导入:有返回值,是文件中exports对象
  4. exports是module.exports的别名,引用了后者的地址,当module.exports={},改变其地址时,exports失效,所以最终以module.exports为准

系统模块(API)

fs文件操作模块
  1. const fs = require(‘fs’)//得到的返回值是fs对象

  2. fs.readFile(‘文件路径/文件名称’[,‘文件编码’],callback)硬盘操作(耗时)

    • callback

      • (err,doc) => {
        	//如果读取错误,err为错误对象(包含错误信息),否则err为null doc为文件内容
        	if(err == null){
        		console.log(doc)
        	}
        }
        
  3. fs.writeFile(‘文件路径/文件名称’,‘数据’,callback)

    • callback

      • err => {
        	if(err != null){
        		console.log(err)
        		return
        	}
        	console.log('文件写入成功')
        }
        
path路径操作

原因:不同操作系统的路径分隔符不统一(window:\或/;linux:/)

  • 路径拼接:path.join(‘路径1’,‘路径2’,…)
  • 获取当前文件所在绝对路径__dirname
  • require可以写相对路径,因为require是相对当前文件

第三方模块(包)

一、js文件:提供实现项目具体功能的API接口
二、以命令行工具形式存在,辅助项目开发

npmjs.com:第三方模块的存储和分发仓库

npm(node package manager):node第三方模块管理工具

  1. nodemon:监控保存操作,自动执行(用nodemon来代替node命令)
  2. nrm:npm下载地址切换工具(nrm ls:可用下载地址列表 nrm use:切换默认下载地址)
  3. gulp:前端构建工具
    • 使用过程
      • npm i gulp//安装gulp
      • npm i gulp-cli -g//全局安装gulp命令行工具
      • 在根目录下创建一个gulpfile.js文件
      • 在命令行工具中,用gulp+任务名即可执行任务
    • 方法
      • gulp.task() 创建任务
      • gulp.src() 获取要处理的文件
      • gulp.dest() 输出文件
      • gulp.watch() 监控文件变化
    • 插件
      • gulp-htmlmin:压缩html
      • gulp-csso:压缩css
      • gulp-uglify:压缩混淆js
      • gulp-babel:ES6 => ES5
      • gulp-less:less => css
      • browsersync:浏览器实时同步
      • gulp-file-include:公共文件抽离
const gulp = require('gulp')
const htmlmin = require('gulp-htmlmin')
const fileinclude = require('gulp-file-include')
const csso = require('gulp-csso')
const less = require('gulp-less')
const uglify = require('gulp-uglify')
const babel = require('gulp-babel')

//1.html任务		压缩html文件  抽取公共部分
gulp.task('htmlmin', () => {
	gulp.src('./src/*.html')
		.pipe(fileinclude())
		.pipe(htmlmin({
			collapseWhitespace: true
		}))
		.pipe(gulp.dest('dist'))
})

//2.css任务		less转换  css压缩
gulp.task('cssmin', () => {
	gulp.src(['./src/css/*.less', './src/css/*.css'])
		.pipe(less())
		.pipe(csso())
		.pipe(gulp.dest('dist/css'))
})

//3.js任务  		ES6转换   js压缩
gulp.task('jsmin', () => {
	gulp.src('./src/js/*.js')
		.pipe(babel({
			presets: ['@babel/env'] //转为ES5语法,一定性要安装多个包 gulp-babel @babel/core @babel/presets?
		}))
		.pipe(uglify())
		.pipe(gulp.dest('dist/js'))
})

//4.复制图片和库文件
gulp.task('copy', () => {
	gulp.src('./src/images')
		.pipe(gulp.dest('dist/images'))
	gulp.src('./src/lib')
		.pipe(gulp.dest('dist/lib'))
})

//5.构建综合任务
gulp.task('default',['htmlmin','cssmin','jsmin','copy'])

package.json

{
  "name": "node01",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "dependencies": {
    "browsersync": "^0.0.1-security",
    "gulp": "^4.0.2",
    "gulp-babel": "^8.0.0",
    "gulp-csso": "^3.0.1",
    "gulp-less": "^4.0.1",
    "gulp-file-include": "^2.1.0",
    "gulp-htmlmin": "^5.0.1",
    "gulp-uglify": "^3.0.2"
  },
  "devDependencies": {},
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

  1. “main”:项目主模块
  2. “dependencies”:项目依赖,(npm i --production:项目运行依赖)
  3. “devDependencies”:开发依赖(线上运营阶段不需要依赖)npm i 包名 --save -dev
  4. “scripts”:命令的别名(“build”:“nodemon app.js” => npm run build)

模块加载机制

  1. 完整路径直接引入
  2. 有路径无后缀
    • 同名js文件
    • 同名文件夹
      • 其中的index.js文件
      • 没有index.js,找当前文件夹的package.json中的“main”的入口文件(此时将find当成一个模块)
        • 指定入口文件不存在、没有指定入口文件 =》报错
  3. 没有路径没有后缀(默认会当成系统模块
    • node_modules中
      • 找同名js文件
      • 同名文件夹
      • 其中的index.js文件
      • 没有index.js,找当前文件夹的package.json中的“main”的入口文件(此时将find当成一个模块)
      • 指定入口文件不存在、没有指定入口文件 =》报错

服务器端概念

  1. 网站的组成

    • 客户端:HTML、Css、Js
    • 服务器端:在服务器运行,负责存储数据和处理应用逻辑
  2. Node网站服务器

    1. 提供网站访问服务的机器,能够接受客户端请求,而且能够对请求作出响应
  3. IP:互联网中设备的唯一标识(域名–》IP:才能找到网站服务器)

  4. 端口:区分服务器电脑中提供不同的服务

  5. URL:统一资源定位符

    传输协议://服务器IP地址/域名:端口/资源所在位置标识
    http   ://www.itcast.cn/	index.html
    
  6. 本机

    • 本机域名:localhost
    • 本机IP:127.0.0.1

创建web服务器

const http = require('http')

const app = http.createSever()
app.on('request',(req,res) => {//为服务器对象添加请求事件
	res.end(req.url)
})
app.listen(3000)//监听3000端口,必须监听,否则无法提供服务
console.log('Sever is running')

http协议

概念

超文本传输协议:客户端(用户)和服务器端(网站)请求和应答的标准

报文
请求报文
  1. req.method:获取请求方式
    • GET:地址栏输入,跳转,表单默认提交方式
      • 参数放在浏览器的地址栏中
      • url.parse(req.url)//将整个url解析为对象
      • url.parse(req.url,true)//将内部的参数也都解析为对象形式
      • url.parse(req.url,true).query//请求参数
      • url.parse(req.url,true).pathname//请求地址
    • POST:表单设置的另一种提交方式
      • 参数放在报文的FormData中
      • post的参数是通过事件来接受的
      • 当请求参数传递的时候触发data事件
      • 当参数传递完成的时候触发end事件
      • 用querystring系统模块来处理post参数
      • querystring.parse(postparams)//将参数转为对象
  2. req.url:获取请求地址(默认是/)
  3. req.headers:获取请求报文信息(对象形式)
  4. request.rawHeaders 全部头信息–数组形式
  5. request.httpVersion 请求的协议方式
响应报文
  1. HTTP状态码
    • 200:成功
    • 404:请求资源未找到
    • 500:服务器端错误
    • 400:客户端请求有语法错误
  2. 常见响应方法
    • res.statusCode=404; //响应码
    • res.statusmessage="not found" //响应消息
    • res.setHeader('Content-Type','text/plain;charset=utf-8')//要放在 res.write() 和 res.end() 之前设置
    • res.writeHead(404,'not found',{'content-type':'内容类型;charset=utf8'})//响应状态码和设置头内容
      • text/html
      • text/css
      • application/javascript
    • res.write("快国庆了,开心!!")
    • res.end()//每个请求都必须调用的方法,==结束响应(请求)==要响应数据的话,数据必须是 String 类型或者是 Buffer 类型

路由

客户端请求地址与服务器端程序代码的对应关系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1aPT1MoG-1571715311772)(C:\Users\明明\AppData\Roaming\Typora\typora-user-images\1571555856606.png)]

静态资源

  1. 概念:服务器端不需要处理,可以直接响应给客户端的资源(谁来请求都一个样)
  2. 动态资源:相同的请求地址,不同的相应资源
    • 根据请求地址、请求类型、设置响应内容类型
  3. mime插件:指定返回资源的类型
    • 将返回的内容类型设置为:mime.getType(req.url)

异步编程

同步API和异步API

  1. 同步API
    • 代码从上至下,逐行执行
    • 可以从返回值中拿结果
    • 前面的代码会阻塞和后面代码
  2. 异步API
    • 当前API的执行不会阻塞后续代码的执行async
    • 只能通过回调函数,将需要返回的值通过回调函数的实参来返回,调用时用回调函数的形参来接受

当需要同步执行异步API时,如果用回调函数来实现,可能会造成回调地狱

const fs = require('fs')

fs.readFile('./1.txt','utf8',(err,result1) => {
    console.log(result1)
    fs.readFile('./2.txt','utf8',(err,result2) => {
        console.log(result2)
        fs.readFile('./3.txt','utf8',(err,result3) => {
            console.log(result3)
        })
    })
})

promise解决回调地狱

const fs  = require('fs')

function p1(){
    return new Promise((resolve,reject) => {
        fs.readFile('./1.txt','utf8',(err,result) => {
                resolve(result)
        })
    })
}

function p2(){
    return  new Promise((resolve,reject) => {
        fs.readFile('./2.txt','utf8',(err,result) => {
                resolve(result)
        })
    })
}

function p3(){
    return new Promise((resolve,reject) => {
        fs.readFile('./3.txt','utf8',(err,result) => {
                resolve(result)
        })
    })
}

p1().then(r1 => {//promise支持链式编程
    console.log(r1)
    return p2()
}).then(r2 => {
    console.log(r2)
    return p3()
}).then(r3 => {
    console.log(r3)
})

异步函数解决解决回调地狱

async function p1(){
    return  'p1'//return 关键字代替resolve,默认返回的是promise对象    throw关键字代替reject
}

async function p2(){
    return  'p2'
}

async function p3(){
    return  'p3'
}

async function getcallback(){
    let r1 = await p1()
    let r2 = await p2()
    let r3 = await p3()
    console.log(r1 ,r2 ,r3)
}
getcallback()

用util.promisify改造异步函数读取文件

const fs  = require('fs')
const promisify = require('util').promisify
const readFile = promisify(fs.readFile)

async function run (){
    let r1 = await readFile('./1.txt','utf8')
    let r2 = await readFile('./2.txt','utf8')
    let r3 = await readFile('./3.txt','utf8')
    console.log([r1,r2,r3])
}
run()

数据库

为什么用数据库
  1. 动态网站中的数据是存储在数据库中的
  2. 能够持久存储客户端通过表单收集的用户信息
  3. 数据库软件本身可以对数据进行高效管理
什么是数据库
  1. 独立于语言之外的软件,可以通过API来操作
  2. 常见数据库软件有:mysql、mongodb、oracle

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tXH6mvD5-1571715311777)(C:\Users\明明\AppData\Roaming\Typora\typora-user-images\1571557954142.png)]

MongoDB可视化软件

是使用图形界面操作数据库的一种方式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uYozUMaI-1571715311782)(C:\Users\明明\AppData\Roaming\Typora\typora-user-images\1571558070078.png)]

数据库相关词汇
  • database:数据库
  • collection:数据集合
  • document:一条数据
  • field:一条数据的属性名
Node通过第三方包mongoose来操作MongoDB(命令行工具)
  1. 启动MongoDB
    • net start mongodb
  2. 关闭MongoDB
    • net end mongodb
  3. 安装mongoose
    • npm i mongoose

连接MongoDB数据库

mongoose.connect('mongoose://localhost/数据库名')//返回值为promise对象=》可以使用异步函数
		.then(() => {console.log('数据库连接成功')})
		.catch(err => {console.log('数据库连接失败',err)})

数据库增删改查

创建集合并新增文档
  1. 设定集合规则

    • const userSchema = new mongoose.Schema({
      	name:String,
      	age:Number
      })
      
  2. 创建集合(两种方式)

    • //创建集合实例,写入文档数据
      const User = new mongoose.model('User',userSchema)//集合在数据库中对应的名字为users
      const user = new User({
      	name:'Melody',
      	age:24
      })
      user.save()//新增文档
      
    • //异步API,返回promise对象,支持异步函数
      const User = new mongoose.model('User',userSchema)//集合在数据库中对应的名字为users
      User.create({name:'Melody',age:24})
      	.then(result => {console.log(result)})
      	.catch(err => {console.log(err)})//直接新增文档
      
查询文档
  • User.find().then(result=>{console.log(result)})//查询多个文档
    //find()参数为键值对,没有条件查询全部,返回值为数组
    
  • User.findOne().then(result=>{console.log(result)})//查询单个文档
    //无条件返回第一个文档
    
  • 查询条件

    • 范围:{key:{$gt:大于值,$lt:小于值}}
    • 包含:{key:{$in:['项']}}
    • 选择查询字段:User.find().select('name age').then(result => {console.log(result)})
    • 根据字段排序:User.find.sort('age').then()
    • 跳过文档数:User.find().skip(2)
    • 限制显示文档数:User.find().limit(3)
删除文档
  • .findOneAndDelete({key:value})//查找并删除单个文档,无条件时删除第一个,返回删除的文档
    
  • .deleteMany({}).then()//删除多个文档,返回{n:删除文档数量,ok:1},不写回调函数无法实现效果
    
更新文档
  • .updateOne({查询条件},{要修改的值}).then()//{}都是键值对形式
    
  • .updateMany({空位所有文档},{要更改的值})//更改多个
    

其他操作

MongoDB数据库导入数据

在命令行输入mongoimport -d 数据库名称 -c 集合名称 --file 要导入的数据文件

mongoose验证

在创建集合规则是,可以为字段设置验证规则,验证失败则插入失败

  • required:必填字段

  • maxlength:最大长度

  • minlength:最小长度

  • trim:去除两端空格

  • min:数值最小值

  • max:数值最大值

  • default:默认值

  • enum:[]枚举可选项

  • 自定义验证器:

    • validate:{
      	validator: v=>return v&&v.length>4,
      	message:'输入用户名不合法'
      }
      
捕获mongoose错误信息
Course.create({name:'移动Web',director:'Pink',isPublished:true})
            .then(result => {console.log(result)})
            .catch(err => {
                const error = err.errors
                for(var attr in error){
                    console.log(error[attr]['message'])
                }
            })
集合关联
const mongoose= require('mongoose')

mongoose.connect('mongodb://localhost/playground')
                .then(() => {console.log('数据库连接成功')})
                .catch(err => {console.log('数据库连接失败')})

const userSchcma = new mongoose.Schema({
    name:String,
    age:Number,
    hobbies:[String],
    email:String
})
const librarySchema = new mongoose.Schema({
    title:'String',
    author:{
        type:mongoose.Schema.Types.ObjectId,
        ref:'User'
    },
    price:String
})
const User = new mongoose.model('User',userSchcma)
const Library = new mongoose.model('Library',librarySchema)

Library.create({
    title:'趁早',
    author:'5c09f267aeb04b22f8460968',
    price:'58'
})
.then(result=> {console.log(result)})
.catch(err => console.log(err))

Library.find().populate('author').then(result => {console.log(result)})

模版引擎–第三方模块art-template

介绍
  1. 优点:

    • 以更加友好的方式拼接字符串
    • 是项目代码更加清晰,易于维护
  2. 基础

    • 安装并引入模版引擎const template = require('art-template')

    • 将数据和模版进行拼接const html = template(模版文件绝对路径,{数据})。举例如下

      • const html = template(artpath,{
            name:'宝宝',
            age:7,
            say:'<h1>哈哈</h1>'
        })
        
模版语法
  • 输出

    • {{name}}//直接输出数据对象的属性值
      {{age}}
      {{@say}}//直接输出数据对象的属性值(html标签及内容)
      <%= 1+2%>//直接输出数据对象的属性值
      <%= age>10 ? '大宝宝' : '小宝贝'%>//直接输出三元表达式运算结果
      <%- say%>//直接输出数据对象的属性值(html标签及内容)
      
  • 条件判断

    • {{if age>7}}
             大宝宝你好
         {{else if age==7}}
             耶又吃成长快乐了
         {{else if age<7}}
             小宝宝你好
         {{/if}}
        
         <% if(age>7){%>
             开始漫长的求学之路
         <% }else if(age==7){ %>
             哈哈哈上小学了
         <% }else if(age<7){%>
             幼儿园真好玩
         <%}%>
      
  • 循环

    • const template = require('art-template')
      const path = require('path')
      
      const artpath = path.join(__dirname,'/views','index.art')
      
      const user = template(artpath,{
          users:[{
              name:'张三',
              age:20,
              hobby:'弹琴唱歌'
          },
          {
              name:'桃桃',
              age:30,
              hobby:'绘画'
          },
          {
              name:'月月',
              age:24,
              hobby:'种植'
          }]
      })
      console.log(user)
      
    •     <ul>
              {{each users}}
                  <li>{{$index}}</li>
                  <li>{{$value.name}}</li>
                  <li>{{$value.age}}</li>
                  <li>{{$value.hobby}}</li>
              {{/each}}
          </ul>
      
          <ul>
              <% for (var i = 0;i < users.length;i++) { %>
                  <li>
                  <%= users[i].name %>
                  <%= users[i].age %>
                  <%= users[i].hobby %>
                  </li>
              <% } %>
          </ul>
      
  • 子模版(抽离公共部分)

    • //在文件中需要的部分引入即可
      {{ include '模版路径' }}
      <% include('模版路径')%>
      
  • 模版继承(HTML骨架模版继承,可以在模版中预留位置)

    • {{extend './layout.art'}}//继承骨架模版的文件
      {{block 'head'}}<link>{{block}}
      
    • 骨架模版

      • <!DOCTYPE html>
        <html lang="en">
        <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">
            {{block 'head'}}{{/block}}
            <title>Document</title>
        </head>
        <body>
            {{block 'content'}}{{/block}}
        </body>
        </html>
        
    • 首页模版

      • {{extend './extend.html'}}
        {{block 'head'}}<link>{{/block}}
        {{block 'content'}}<p>哈哈哈</p>{{/block}}
        
模版配置
  • 向模版导入变量,举例dateFormat(日期格式处理工具)

    • const dateFormat = require('dateformat')
      template.defaults.imports.变量名=dateFormat//第三方方法,在模版中即可使用
      
  • 模版根目录及后缀配置

    • template.defaults.root=根目录//设置根目录
      
    • template.defaults.extname='.art'或者'.html'//设置后缀名
      
    • 配置过后,模版路径只写文件名即可

第三方模块:router(路由)

const getRouter = require('router')
const router = getRouter()
router.get('/add',(req,res) => {
    let add = template('index',{})
    res.end(add)
})
app.on('request',(req,res) => {
    router(req,res,() => {
    })//调用router方法
})

第三方模块:serve-static(静态资源服务)

const serveStatic = require('serve-static')
const serve = serveStatic(path.join(__dirname,'public'))
app.on('request',(req,res) => {
    serve(req,res,() => {
    })//调用serve方法
})

Express框架

  • node的第三方模块,是web应用开发框架

  • 优点:

    • 简洁的路由:express.Router()
    • 简化服务器创建:const app = express()
    • 简化http请求参数处理:
      • app.get(’/’,(req,res)=>{req.query/req.params})
      • app.post(’/add’,(req,res)=>{req.body})
    • 对模版引擎支持度高
  • 流程

    const express = require('express')//引包
    const app = express()//创建服务器
    app.get('/',(req,res)=>{//接受get请求
    	res.send(req.query/req.params)//.send()优点:检测响应类型,自动设置响应的内容类型及编码,自动设置http状态码
    })
    

中间件

中间件就是一堆方法,用来处理请求,可以将复杂的请求由多个中间件进行多次处理

  • 中间件方法:由Express提供,负责连接请求,eg:app.get(),app.use()等
  • 请求处理函数:开发人员提供,负责处理请求,eg:(req,res,next)=>{}
应用
  1. 路由保护:先app.use()判断用户的登陆状态,然后决定是否next()
  2. 网站维护公告:在所有路由的最前
  3. 404:在所有路由的最后(res.status(404).send(‘404’))
错误处理中间件:集中处理预料之外的错误
app.use((err,req,res,next) => {
	res.status(500).send('服务器端错误')
})
app.get('index',(req,res)=>{
	throw new Error('程序发生未知错误')
})
app.get('index',(req,res,next)=>{
	fs.readFile('./demo.txt','utf8',(err,result)=>{
		if(err!=null){
			next(err)//异步API触发错误处理中间件
		}else{
			res.send(result)
		}
	})
})
捕获错误

异步函数和其他同步代码,用try catch

app.get('index',async (req,res,next)=>{
	try{
		await User.find({name:'zs'})
	}catch(ex){
		next(ex)//手动触发错误处理中间件,将错误信息传给下一个中间件
	}
})
构建模块化路由

将多个路由模块抽离出去,在app.js中调用即可

app.use(’/home’,home)//后面是路由对象

app.use(’/admin’,admin)

参数获取

get参数:

req.query/req.params

post参数:

const bodyParser = require('body-parser')
app.use(bodaParser.urlencoded({extend:false}))//false:方法内部用querystring处理,true:方法内部调用第三方模块qs处理
req.body

Express路由参数

app.get('/find/:id',(req,res)=>{})//用占位符来对顶请求路径必须包含参数
静态资源访问

express.static(‘目录’)//托管静态资源

app.use(express.static(‘目录’))//拦截所有请求,交给express.static()方法来处理,如果是静态资源会终止请求并处理,不是则next()交给下一个中间件处理

模版引擎

express进一步封装了art-template

npm i art-template express-art-template

app.engine('art',require('express-art-template'))//配置模版引擎处理后缀名为art的模版文件
app.set('views',模版文件夹根目录)//模版引擎配置项views,默认根目录
app.set('view engine','art')//模版引擎配置项view engine,默认后缀名
app.get('/',(req,res)=>{
	res.render('index',{//index是省略了根目录和后缀名的模版文件
		msg:'message'//数据
	})
})
app.locals对象
app.locals.users=[{//users设置在locals下,可以在所有模版中使用
	name:'zs',
	age:18
},{
	name:'ls',
	age:12
}]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值