node基础 ,nodejs的express框架(三)
启程express
-
安装
npm i express -S
-
1:引入express第三方对象
-
-
3:开启服务器监听端口
-
4:处理响应
-
在express中,保留了原生http的相关属性和函数
app.use(路由路径,fn)
-
小练习
-
选择性荤菜素菜
-
-
用户/abc/def的请求
-
选择性调用app.use('/abc',fn)的中间件
-
但是内部req.url则去除了/abc这个暗号
-
-
app.use(fn)是任何请求都会触发执行的
中间件类别(请求与响应之间的事情)
-
应用级中间件
app.use(事fn)
-
路由级中间件
-
1:获取路径级中间件
-
2:配置路由
-
3:加入到应用程序控制中
app.use(router);
-
-
内置中间件
-
处理一些静态资源文件的返回(设置将某个目录下的资源文件向外暴露)
-
当url匹配上我设置的目录下的子文件后,自动返回该文件
-
加入到应用程序控制中
app.use(内置中间件);
-
-
-
第三方中间件
-
更方便的处理cookie/session,简易的解析post请求体数据
-
在npm上下载并使用
-
加入到应用程序控制中
app.use(第三方中间件);
-
-
错误处理中间件
-
在express中统一处理错误
next(err)
-
路由中间件
-
一个请求进来(总网线),分发到各自不同的处理(分多根网线给其他人)
-
分流
-
-
后端路由
-
(请求方式 + URL = 判断依据)(分流的判断依据) -> 做不同的处理(分流后的行为)
-
-
使用步骤
-
1:获取路由中间件对象
let router = express.Router();
-
2:配置路由规则
router.请求方式(URL,fn事)
-
fn中参数有req,res,next
-
-
3:将router加入到应用
app.use(router)
-
路由
res扩展函数
res.download('./xxx.txt') // 下载文件
res.json({}) // 响应json对象
res.jsonp(数据) // 配合jsonp 要求客户端请求的时候也是jsonp的方式, 并且callback=xxx
res.redirect() // 重定向 301是永久重定向, 302临时重定向
res.send() // 发送字符串数据自动加content-type
res.sendFile() // 显示一个文件
res.sendStatus() // 响应状态码
-
总结
-
res.json() 响应数据,最常用 , 返回ajax数据
-
redirect() 重定向
-
download() 下载
-
-
jsonp() 跨域处理
模板渲染
使用art-template模板引擎
-
下载express-art-template art-template
-
app.js中配置
-
注册一个模板引擎
-
app.engine('.html',express-art-template);
-
设置默认渲染引擎
app.set('view engine','.html');
-
-
-
res.render(文件名,数据对象);
-
-
服务端处理错误和404页面找不到
-
404页面响应
router.all('*',()=>{} )
-
触发错误
-
-
处理错误 app.use( 4参数函数 )
-
nodemon
-
修改代码自动重启
-
安装全局命令行工具
npm i -g nodemon
-
进入到指定目录命令行
nodemon ./xxx.js
server1.js
// - 1:引入express第三方对象 const express = require('express'); // - 2:构建一个服务器对象 // 原生的 // let server = http.createServer(); let app = express(); // - 3:开启服务器监听端口 app.listen(8888,()=>{ console.log('服务器启动在8888端口'); }); // - 4:处理响应 // 1: app.use是请求与响应中执行的一件事,按代码顺序来执行 // 2:next() 是放行到下一件事的开关 // 3:如果全next,最终没有end页面数据,框架帮我们处理了 // status:404 // 用户选择性url开头的部分,选择性调用对应的事 app.use('/sucai',(req,res,next)=>{ console.log('萝卜'); next(); // 放行开关 }); // 一件事 app.use('/sucai',(req,res,next)=>{ console.log('白菜'); next(); }); app.use('/huncai',(req,res,next)=>{ console.log('牛肉'); next(); }); app.use('/huncai',(req,res,next)=>{ console.log('羊肉'); next(); });
server2.js
const express = require('express'); let server = express(); // - 1:获取路由中间件对象 let router = express.Router(); let router = express.Router(); // - 2:配置路由规则 router.请求方式(URL,fn事) router.get('/login',(req,res) => { res.end('login page'); }) .get('/register',(req,res) => { res.end('register page'); }) // - fn中参数有req,res,next // - 3:将router加入到应用server.use(router) server.use(router); server.listen(8888);
server3.js
const express = require('express'); let server = express(); // - res.json() 响应json数据,最常用 , 返回ajax数据 // - redirect() 重定向 // - download() 下载 // - jsonp() 跨域处理 // - 1:获取路由中间件对象 let router = express.Router(); let router = express.Router(); // - 2:配置路由规则 router.请求方式(URL,fn事),链式调用 router.get('/json',(req,res) => { res.json([{name:'jack'}]); // res.end只能响应string||读文件中的data Buffer }) .get('/redirect',(req,res) => { // 重定向到百度 res.redirect('http://www.baidu.com'); }) .get('/jsonp',(req,res) => { res.jsonp('jack love rose'); }) .get('/download',(req,res) => { res.download('./app.js'); // app.js,注意文件是如何被下载成功的 // 基于服务器回写的content-type。等头信息 }) // - 3:将router加入到应用server.use(router) server.use(router); server.listen(8888);
server4.js, 模板渲染,将html文件返回给浏览器,重要
const express = require('express'); let server = express(); // / - 注册一个模板引擎 // - app.engine('.html',express-art-template); // 渲染文件的后缀名(引擎名称) server.engine('.html',require('express-art-template')); // 区分开发和生产环节的不同配置,了解即可 // server.set('view options', { // debug: process.env.NODE_ENV !== 'production', // // debug : 不压缩,不混淆,实时保持最新的数据 // // 非debug: 压缩/合并, list.html 静态数据不回实时更新(服务器重启才更新) // imports:{ // // 数据的导入,和过滤显示的操作 // num:1, // reverse:function(str) { // return '^_^' + str + '^_^'; // } // } // }); // 配置默认渲染引擎,就是ssr渲染,将html返回给浏览器,默认去找与server4.js同级的view文件夹的.html文件 server.set('view engine','.html'); let router = express.Router(); router.get('/hero-list',(req,res) => { res.render('list.html',{ heros:[{name:'貂蝉'},{name:'吕布'},{name:'董卓'}] }); }) server.use(router); server.listen(8888);
server5.js, 服务端处理错误和404找不到页面
const express = require('express'); const fs = require('fs'); let server = express(); server.engine('.html',require('express-art-template')); // server.set('view options', { // debug: process.env.NODE_ENV !== 'production', // }); // 配置默认渲染引擎 server.set('view engine','.html'); let router = express.Router(); router.get('/',(req,res,next) => { console.log('请求进来了?',req.url); // 目录下没有该文件,会读取不到文件 let errorPath = './abc/e.txt'; try { // 同步读取服务器中的文件 fs.readFileSync(errorPath); // 将view文件夹下index.html返回 res.render('index'); } catch (err) { // throw err; // 给用户看到了异常,太恶心 next(err); // 触发一个具备4个参数的中间件函数 } }) // 最后一条路由中,不论什么请求方式,什么路径,比如地址栏输出服务端没处理的/user路由 .all('*',(req,res)=> { res.send('地址错误,您去首页吧'); }) // 要把public下的文件暴露出来 // server.use('/public',express.static('./public')); // 当虚拟目录/public被匹配以后,未来url都会去除掉/public server.use(router); // 没找到正确的html返回,比如用户地址栏输入/根路径,但是读取文件有错误 处理错误(参数位置错误优先) -> 优雅的用户体验 server.use((err,req,res,next) => { res.send('<h1>亲爱的用户,您访问的页面,有事儿了,<a href="/">去首页看看?</a></h1>'); }) server.listen(8888);
注;1.服务器只处理了/根路由, 如果用户地址栏输入/user, 服务器没有处理这个路由,那么会报错,所以需处理router.all(),来提示错误,404
2.如果用户地址栏是/更路径,但是服务器读取文件时有错误,需要server.use(),来处理错误。
这两种优化处理错误方式都很常见