博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
1206-express路由&参数获取&中间件 & 响应方法扩展
阅读量:7142 次
发布时间:2019-06-29

本文共 6713 字,大约阅读时间需要 22 分钟。

express nodejs Web应用开发框架

安装

  • npm install express ejs body-parser --save

使用

//引用express模块,他是一个函数let express = require('express');//express函数执行后,返回的是一个http的监听函数app,就是http.createServer中的函数let app = express();//在app函数上扩展了一个listen的方法,可以监听端口app.listen(3000,()=>{    console.log(`服务启动在3000端口`)})//=>剖析app.listen都做了什么? 启动了一个http服务,把监听函数传进去,并且监听了端口。app.listen  = (...args)=>{    require('http').createServer(this).listen(...args)}复制代码

主要功能:

  • 路由控制
  • 参数获取(req扩展的方法)
  • 中间件
  • send 和sendFile(res扩展的方法)
  • 静态文件服务
  • 模版解析
  • 重定向

主要功能分析

  • 路由控制 express-route.js
/*    app监听函数上,扩展了很多方法,包括get post put...等,restful风格中的动词;    app.all("*",cb) 表示匹配任何动词 任何路径    app.方法名(路径,cb) => 匹配的是只是请求路径pathname,并且不包含?参数,而且是严格匹配;    特点:从上到下匹配,如果匹配到了并且结束响应,就不会继续向下继续走了。*/let express = require('express');let app = express();app.listen(3000,()=>{
console.log(`服务运行在3000端口`)})app.get('/signin',(req,res)=>{ res.setHeader('Content-Type','text/plain;charset=utf8') res.end('登录')})app.post('/signup',(req,res)=>{ res.setHeader('Content-Type','text/plain;charset=utf8'); res.end(post注册)})//all 表示所有动词方法, * 表示匹配任何路径。一般放到最后app.all('*',(req,res)=>{ res.end(404)})复制代码
  • 参数获取
/*    req.query =>url.parse(req.url,true).query 取?参数    req.path = >url.parse(req.url,true).pathname 取路径    req.url //请求路径+?参数    req.headers //是一个对象,key和value全部是小写的    req.method //请求方法,全部是大写的    req.params //路径参数,后续会讲到    app.param('id',(req,res,next))根据路径参数拦截请求*/let express = require('express')let app = express();app.listen(3000)app.get('/user',(req,res)=>{    console.log(req.query.id)    console.log(req.url)    console.log(req.path)    console.log(req.headers)    console.log(req.method)    if(req.query.id){        //查一个用户    }else{        //查询所有用户    }})--------//利用路径参数,区分是查一个用户还是查所有用户let express = require('express');let app = express();app.listen(3000)app.get('/user',(req,res)=>{    res.end('select All')})// /user/1/qiaoshi//id表示占位符,必须有,但是可以随便写;app.get('/user/:id/:name',(req,res)=>{    console.log(res.params) // {id:1,name:qiaoshi}    res.end(`select one ${req.params.id}${req.params.name}`)})//js实现 提取路径参数;let url = '/user/1/xiaoming';let path = '/user/:id/:name';let keys = []let newPath = path.replace(/:([^\/]+)/g,function(...args){    keys.push(args[1])    return '([^\/]+)';})let reg = new RegExp(newPath);let values = reg.exec(url);let params = {};keys.forEach((key,index)=>{    params[key] = values[index+1]})console.log(params)---------//利用app.param中间件,拦截路径参数,进行过滤,还可以进行其他操作let express = require('express')let app =express();app.listen(3000)app.param('id',(req,res,next)=>{    req.params.id = `你的学号是${req.params.id}`   //res.end(); ·    next();//调用next,就继续向下匹配;})app.param('name',(req,res,next)=>{    req.params.name = '你的名字是${req.params.name}'    next()})app.get('/user/:id/:name',(req,res)=>{    res.header('Content-Type','text/plain;charset=utf-8')    res.end(req.params.id + req.params.name)})复制代码
  • 中间件,当我们访问到最终目标之前 需要执行的内容
/*功能:1.可以进行权限判断      2.可以对req res的属性进行扩充      3.中间件放到最终目标钱穆庵      4.中间件默认情况下,匹配路径'/';也可以指定匹配以什么开头的,以目录级数为单位;          特殊:调用next传递了参数 =>错误中间件,四个参数=>  app.use((req,res,next,err)=>{console.log(err)})          如果res.end,关闭了响应,在调用next,会继续匹配,但是响应已经关闭,返回给了客户端,后续的匹配毫无意义;*/let express =require('express');let app = express();app.listen(3000);//app.use((req,res,next){})//不写路径,默认匹配'/',匹配任何路径;app.use('/water',(req,res,next)=>{    console.log('过滤石头');    req.stone = 'too big'    next();//不调用next,就不会继续向下走})app.use('/water',function(req,res,next)=>{    console.log('过滤沙子');    req.sand = ' too small'    next();})app.use((req,res,next)=>{
//利用中间件匹配所有,统一设置响应头编码和mime类型 res.setHeader('Content-Type','text/plain;charset=utf8'); next()})app.get('/water',(req,res)=>{
//会过滤 console.log('过滤完成') console.log(req.stone,req.sand) res.end('水')})app.get('/water/a',(req,res)=>{ //会过滤 console.log('过滤完成') console.log(req.stone,req.sand) res.end('水')})app.get('/food',function (req, res) { //不会通过 /water的中间件进行过滤 console.log(req.stone,req.sand) //undefined undefined res.end('食物')})//错误中间件,拥有四个参数,fn.length = 4; //触发:当前面的中间件 调用next传递了参数时,就认为报错了,就会执行错误中间件app.use((err,req,res,next)=>{ console.log(err)})复制代码
  • 中间件的装饰模式
//中间件装饰模式-就是在已有方法的基础上包装一层,生成新的方法,但不影响已有方法的功能,同时还扩展了自己的js逻辑let express = require('express');let app = express();app.listen(3000)app.use('/eat',(req,res,next)=>{    let t = new Date().getTime();    let end = res.end;    res.end = (...args)=>{        end.call(res,...args);        console.log(new Date().getTime() - t)//计算每个接口请求的耗时    }})app.get('/eat/water',(req,res)=>{    for(let i = 0 ;i<10000;i++){            }    res.end('water')})app.get('/eat/food',(req,res)=>{    for(let i = 0 ;i<10000000;i++){            }    res.end('food')})复制代码
  • js模拟express 中间件 next方法思路:
function app (){    }//每次调用use方法,都会将方法存到数组中;app.middleWares = []app.use = function(cb){    this.middleWares.push(cb)}app.use((req,res,next)=>{    console.log(1)    next()})app.use((req,res,next)=>{    console.log(2)    next()})app.use((req,res,next)=>{    console.log(3)})//默认调用数组第一项,将next方法传递给数组中的方法;如果调用next 会继续执行数组中的下一项let i = 0;function next(){    app.middleWares[i](null,null,next);    i++;}next();复制代码
  • res 扩展的方法 send sendFile json sendStatus
/*res.json({name:1})  =>res.end(JSON.stringify({name:1})) 以前只能写入buffer和字符串,现在直接json,而且不用考虑utf8编码问题res.sendStatus(200) = > res.statusCode = 200;res.end('ok') res.send() =>res.end() res.setHeader() //支持返回文本、json、状态吗等,最常用,不用考虑编码;res.sendFile() => fs读取流然后pie;// 直接返回文件,不过要填绝对路径;//sendFile不能通过../去查找上一级,root不支持。//如果需要返回上一级的文件,需要用path模块拼接绝对路径;path.join(__dirnmae,'..','index.html)//res.header('Content-Type','text/plain;charset=utf8'); =>res.setHeader() 设置响应头*/let express = require('express');let app = express();app.listen(3000);app.get('/json',(req,res)=>{    res.json({
name:'小明'})})app.get('/',(req,res)=>{ res.sendFile('./index.html',{
root:__dirname}); //等价于res.sendFile(__dirname+'/index.html') res.sendFile(require('path').join(__dirname,'..','index.html'))//上一级目录的文件})app.get('/status',(req,res)=>{ res.sendStatus(200) //OK 404 =>not found});//js模拟扩展实现send方法app.use(function(req,res,next){ req.mySend = function(data){ if(typeof data =='object'){ res.setHeader('Content-Type','application/json;charset=utf8') res.end(JSON.stringify(data)) return } if(typeof data =='string'){ res.setHeader('Content-Type','text/plain;charset=utf8') res.end(data) return } if(typeof data = 'number'){ res.statusCode = data; let _http_server = require('_http_server');// res.end(_http_server.STATUS_CODES[data])//状态码信息映射表 return } next() } })app.get('/send',(req,res)=>{ //res.send({name:'小明'})//send方法会自己判断传入的值是什么类型 //res.send(200) //res.send('中文') res.mySend(404)})复制代码

转载地址:http://fnwgl.baihongyu.com/

你可能感兴趣的文章
带你一分钟理解闭包--js面向对象编程
查看>>
MySql基本使用方法
查看>>
LAME的“命令行”
查看>>
PyQt5学习-day1 -4 退出按钮
查看>>
使用Parallel.Invoke并行你的代码
查看>>
口袋笔记VS松鼠笔记
查看>>
silverlight 将chart图倒入到excel
查看>>
LeetCode – Refresh – Word Search
查看>>
ADO.NET笔记——使用Connection连接数据库,使用Command对象的ExecuteReader()方法创建DataReader对象返回多行数据...
查看>>
HDU sum问题
查看>>
C语言基础知识汇总
查看>>
数字高程模型和地图——thematicmapping.org译文(一)
查看>>
8-5 泛型类型擦除
查看>>
正文处理命令及tar命令
查看>>
实习第三周小记-----生活在于经历 分类: 程序人生 ...
查看>>
将excel中的数据转为json格式
查看>>
字典操作
查看>>
[洛谷P2839][国家集训队]middle
查看>>
《求一个数组的连续的最大子数组之和》
查看>>
设置行间距,自适应文字大小
查看>>