Express 入门
什么是Node?
-
Node 发布于 2009 年
-
Node(正式名称Node.js)是一个开源的、跨平台的运行时环境
第一个Hello World
// 调用 HTTP 模块
const http = require("http");
// 创建 HTTP 服务器并监听 8000 端口的所有请求
http.createServer((request, response) => {
// 用 HTTP 状态码和内容类型来设定 HTTP 响应头
response.writeHead(200, {'Content-Type': 'text/plain'});
// 发送响应体 "Hello World"
response.end('Hello World\n');
}).listen(8000);
// 在控制台打印访问服务器的 URL
console.log('服务器运行于 http://127.0.0.1:8000/');
//运行代码后,在浏览器在浏览器地址栏中输入 "http://localhost:8000" 并按回车,可以看到一个大面积空白的网页,左上角有 “Hello World" 字样
什么是Express?
Express 是最流行的 Node 框架,是许多其它流行 Node 框架 的底层库。它提供了以下机制:
- 为不同 URL 路径中使用不同 HTTP 动词的请求(路由)编写处理程序。
- 集成了“视图”渲染引擎,以便通过将数据插入模板来生成响应。
- 设置常见 web 应用设置,比如用于连接的端口,以及渲染响应模板的位置。
- 在请求处理管道的任何位置添加额外的请求处理“中间件”。
第一个Hello Express
//导入express模块
const express = require('express')
//创建express应用
const app = express()
//路由定义 监听根目录路径('/')的HTTPget请求时调用回调函数
/*
* 参数:
* req:请求对象,包含请求的信息及客户端传递的数据
* res:响应对象,主要负责将服务器处理的结果返回给客户端
*/
app.get('/',(req,res) => {
res.send('Hello Express!')
})
//控制在3000端口上启动服务器并在控制台打印日志
app.listen(3000,() => {
console.log('示例应用正在监听 3000 端口!')
})
Express核心概念
中间件
中间件可以理解成一个对请求进行过滤和预处理的东西,但他不会直接对客户端进行响应,而是将处理之后的结果向下传递,例各种应用逻辑,如cookie解析、会话处理、日志记录、权限校验等,都是通过中间件来完成的。
基本用法
get请求、post请求
const express = require('express')
const app = express()
//中间件的基本使用(get、post请求)
/*
* next
* 第三个参数,表示继续匹配下一项相同路由
*/
app.get('/',(req,res,next)=>{
req.name = 'zhangsan'
next() //继续匹配下一项
})
app.get('/',(req,res)=>{
res.send(req.name)
})
app.listen(3000,(err)=>{
if(err){
console.log(err)
return
}
console.log('服务启动成功')
})
中间件应用
app.use() 参数需要一个函数
匹配所有请求方式,可以直接传入请求处理函数,代表接收所有的请求
- 路由保护
- 网站维护公告
- 自定义404页面
const express = require('express')
const app = express()
//当访问admin页面时,返回zhangsan
app.get('/admin',(req,res)=>{
res.send('zhangsan')
})
//匹配全部路由
app.use((req,res,next)=>{
//链式调用,status设置状态码
res.status(404).send('当前页面不存在!')
})
app.listen(3000)
错误处理中间件
一个集中处理错误的地方,包含四个参数,错误处理中间件可以任何所需内容,但是必须在所有其它
app.use()
和路由调用后才能调用,因此它们是需求处理过程中最后的中间件。
const express = require('express')
const fs = require('fs')
const app = express()
const promisify = require('util').promisify
const readFile = promisify(fs.readFile)
//当访问admin页面时,读取index.js文件,若出错,将错误信息传递给next()
app.get('/admin',(req,res,next)=>{
fs.readFile('./index.js',(err,data)=>{
if(err){
next(err)
}
})
})
//当访问about页面时(异步出错)
app.get('/about',async (req,res,next)=>{
try{
await readFile('./aaa.js')
}catch(err){
next(err)
}
})
//当访问index页面时,直接内建一个错误
app.get('/index',(req,res,next)=>{
throw new Error('出错了!')
})
//匹配全部路由
app.use((err,req,res,next)=>{
//链式调用,status设置状态码
//接收错误信息,err.message == err(next)|| '出错了'(Error)
res.status(404).send(err.message)
//res.status(404).send('出错')
})
app.listen(3000)
/*
* 浏览器访问结果:
* admin -- ENOENT: no such file or directory, open 'D:\node\index.js'
* index -- 出错了
* about -- ENOENT: no such file or directory, open 'D:\node\aaa.js'
*/
静态资源托管
通过
express.static
中间件来托管静态文件
static()
是 Express 提供的原生中间件函数之一
const express = require('express')
const app = express()
// 托管静态资源,浏览器中可以直接访问public下文件
/*
* http://localhost:3000/images/dog.jpg
* http://localhost:3000/css/style.css
* http://localhost:3000/js/app.js
*/
app.use(express.static('public'))
app.listen(3000)
/*
* 可以通过多次调用 static() 来托管多个文件夹。如果一个中间件函数找不到某个文件,将直接传递给下一个中间件(中* 间件的调用顺序取决于声明顺序)
* app.use(express.static('public1'))
* app.use(express.static('public2'))
*/
/*
* 还可以为静态 URL 创建一个虚拟的前缀,而不是直接把文件添加到根 URL 里
* app.use('home',express.static('public'))
* 浏览器访问模式
* http://localhost:3000/home/images/dog.jpg
* http://localhost:3000/home/css/style.css
* http://localhost:3000/home/js/app.js
*/
路由(中间件)
基础路由
- get()
- post()
- put()
- delete()
- ……
模块化路由
//home.js
const express = require('express')
//创建路由对象
const home = express.Router()
//路由下创建二级路由
home.get('/index',(req,res)=>{
// /about/index
res.send('home')
})
// 导出模块
module.exports = home
//about.js
const express = require('express')
const about = express.Router()
about.get('/index',(req,res)=>{
res.send('about')
})
module.exports = about
//app.js
const express = require('express')
const app = express()
//引入模块
const home = require('./route/home')
const about = require('./route/about')
//将路由和请求路径进行匹配
app.use('/home',home)
app.use('/about',about)
app.listen(3000)
路由参数获取
get()参数获取
express框架中使用req.query查询参数
//http://localhost:3000/?name=zhangsan&age=20 //接收地址栏中?后边的参数 const express = require('express') const app = express() app.get('/',(req,res)=>{ res.send(req.query) }) app.listen(3000) //浏览器:{"name":"zhangsan","age":"20"}
post()参数获取
post()参数获取需要借助express框架的第三方包body-parser
const express = require('express') const bodyParser = require('body-parser') const app = express() /* * 拦截所有请求 * extended:true,方法内部使用querystring模块处理请求参数的格式 * extended: false,方法内部使用第三方模块qs处理请求参数的格式 */ app.use(bodyParser.urlencoded({extended:false})) app.post('/add',(req,res)=>{ //响应请求参数 res.send(req.body) }) app.listen(3000)
<body> <form action="http://localhost:3000/add" method="POST"> <input type="text" name="user"> <input type="password" name="psd"> <input type="submit" name="" id=""> </form> </body> // 注意:这里表单必须设置name属性 //提交后 {"user":"zhangsan","psd":"123456"}
拓展(自定义中间件)
const express = require('express') const app = express() app.use(fn({a:2})) function fn(obj){ //必须返回一个函数 return function(req,res,next){ if(obj.a == 1){ console.log(req.url) }else{ console.log(req.method) } next() } } app.get('/',(req,res)=>{ //响应请求参数 res.send('welcome') }) app.listen(3000)
路由参数设置
//通过 :3000/admin/zhangsan/30/男 发起请求
const express = require('express') const app = express() app.get('/admin/:user/:age/:sex',(req,res)=>{ //响应请求参数 res.send(req.params) }) app.listen(3000) //页面请求 {"user":"zhangsan","age":"30","sex":"男"}
模板引擎
为了使
art-template
能够和express框架更加的配合,官方在art-template
的基础上封装了express-art-template
所以想要使用模板引擎我们两个都要需要安装
npm i art-template express-art-template
基本使用
默认渲染的文件夹views需要自己创建
创建views文件夹
在views文件夹下放模板index.art
//app.js
const express = require('express')
const path = require('path')
const app = express()
//1.告诉express框架使用什么样的模板引擎渲染什么后缀的模板文件
/**
* 参数
* 1. 模板后缀
* 2. 使用的模板引擎
*/
app.engine('art',require('express-art-template'))
//告诉express框架模板存放的位置
app.set('views',path.join(__dirname,'views'))
//告诉express框架模板的默认后缀是什么
app.set('views engine','art')
app.get('/index',(req,res)=>{
/**
* render函数
* 1. 拼接模板路径
* 2. 拼接模板后缀
* 3. 将对应的模板和数据进行拼接
* 4. 将拼接结果返回给客户端
*/
//在此处不写后缀时,将使用默认后缀
res.render('index.art',{
msg:'message'
})
})
app.listen(3000)
//页面输出 message
//index.art
{{ msg }
基本语法(标准)
输出
{{value}} {{data.key}} {{data['key']}} {{a ? b : c}} {{a || b}} {{a + b}}
原文输出
{{@ value }} //原文输出语句不会对 HTML 内容进行转义处理,可能存在安全风险,请谨慎使用
条件
{{if value}} ... {{/if}} {{if v1}} ... {{else if v2}} ... {{/if}}
循环
{{each target}} {{$index}} {{$value}} {{/each}}
变量
{{set temp = data.sub.content}}
模板继承
{{extend './layout.art'}} {{block 'head'}} ... {{/block}}
子模板
{{include './header.art'}} {{include './header.art' data}}
过滤器
template.defaults.imports.dateFormat = function(date, format){/*[code..]*/}; template.defaults.imports.timestamp = function(value){return value * 1000};