node中的模块导入和导出

  • 在node中使用module.exports导出一个模块

  • 在node中使用require导入一个模块 ```javascript function add(a,b){ return a+b; } module.exports = add//导出一个模块

const add=require(“./index”)//导入一个模块,其中require是一个函数,接收一个路径作为参数 const sum=add(10,20); console.log(sum)

//在导入模块的过程中可以按需导入,前提是导出的是一个对象=>es6中的解构赋值 const {name,add}=require(“./index”)

  1. <a name="fae773c5"></a>
  2. ### 在node中创建一个http服务
  3. -
  4. 通过`http`模块创建一个http服务
  5. ```javascript
  6. //http.createServer创建一个http服务
  7. //获取请求头req.headers["content-type"]
  8. const server=http.createServer((req,res)=>{
  9. // writeHead()方法用于设置响应数据的响应头headers
  10. //第一个参数为响应的状态码,第二个参数为响应头
  11. res.writeHead(200,{"content-type":"text/html"})//设置响应数据的响应头
  12. res.end("<h1>hello word</h1>")//发送响应信息
  13. })
  14. //监听一个3000端口
  15. server.listen(3000,()=>{
  16. console.log("创建一个http服务成功")
  17. })
  • 处理get请求 ```javascript const http = require(“http”); const querystring = require(“querystring”);

const server=http.createServer((req,res)=>{ console.log(req.method)//返回请求的方式 const url=req.url; console.log(“请求的url地址:”+url); req.query=querystring.parse(url.split(“?”)[1])//parse默认使用&分割查询字符串 console.log(req.query) res.end( JSON.stringify(req.query)//向前端返回json格式的数据 ) }) server.listen(3000,()=>{ console.log(“创建服务成功”) })

  1. -
  2. 处理post请求
  3. ```javascript
  4. const http = require("http");
  5. const server=http.createServer((req,res)=>{
  6. if(req.method==='POST'){
  7. //req的数据格式
  8. console.log("req content-type:"+req.headers['content-type'])
  9. }
  10. //接收到的数据
  11. let postData="";
  12. //监听请求数据的发送
  13. req.on("data",chunk=>{
  14. postData+=chunk.toString();
  15. })
  16. //监听数据发送结束
  17. req.on("end",()=>{
  18. console.log(postData)
  19. res.end("请求发送成功")
  20. })
  21. })
  22. server.listen(3000)
  • node综合处理get和post请求 ```javascript const http = require(“http”); const querystring = require(“querystring”);

const server=http.createServer((req,res)=>{ const method=req.method;//获取请求的方式

const url=req.url;//获取前端请求的url地址

const path=url.split(“?”)[0]//获取前端的网页地址

const query=querystring.parse(url.split(“?”)[1])//获取查询字符串

//设置返回的数据为json

//设置响应数据的响应头 res.setHeader(“Content-type”,”application/json”); //返回的数据 const resData={ method,url,path,query }

  1. if(method==='GET'){
  2. res.end(
  3. JSON.stringify(resData)//设置返回字符串的格式
  4. )
  5. }
  6. else if(method==='POST'){
  7. let postData=""
  8. //监听前端发送过来的数据,当前端有数据发送过来时,传递给chunk
  9. req.on("data",(chunk)=>{
  10. postData=chunk.toString()
  11. })
  12. //监听前端发送数据结束,执行回调函数
  13. req.on("end",()=>{
  14. resData.postData=postData;
  15. res.end(
  16. JSON.stringify(resData)//设置返回字符串的格式
  17. )
  18. })
  19. }

}) server.listen(3000)

  1. <a name="202459f0"></a>
  2. ### nodemon使用
  3. -
  4. nodemon检测文件变化,自动重启node
  5. ```javascript
  6. //安装nodemon cnpm i nodemon -g
  7. //安装cross-env cnpm i cross-env -S
  8. //配置
  9. "scripts": {
  10. "test": "echo \"Error: no test specified\" && exit 1",
  11. "dev":"cross-env NODE_ENV=dev nodemon ./bin/www.js",
  12. "prd":"cross-env NODE_ENV=production nodemon ./bin/www.js"
  13. }
  14. //创建响应文件 ./bin/www.js
  • cross-env是用来设置不同的运行环境

node中的cookie和session

cookie

  • 存储在浏览器中的一段字符串(最大5kb)
  • 跨域不共享

server操作cookie

  1. //获取cookie
  2. //解析cookie
  3. req.cookie={}
  4. const cookieStr=req.headers.cookie||""//cookie的格式是k1=1;k2=2;k3=3
  5. cookieStr.split(";").forEach(item=>{
  6. if(!item){
  7. return
  8. }
  9. const arr=item.split("=")
  10. const key=arr[0]
  11. const val=arr[1]
  12. req.cookie[key]=val
  13. })
  14. //设置cookie的值,path参数表示这个cookie可以在所有的网页都能访问,httpOnly参数限制cookie不能修改
  15. //expires参数设置cookie的过期时间
  16. const getCookieExpire = () => {
  17. const d = new Date();
  18. d.setTime(d.getTime() + (24 * 60 * 60 * 1000))
  19. return d.toGMTString();
  20. }
  21. res.setHeader("Set-Cookie", `username=${data.username};path=/;httpOnly;expires=${getCookieExpire()}`)

session

  1. const SESSION_DATA = {}
  2. //解析session
  3. let needSetCookie=false//标志userid是否已经存在
  4. let userId = req.cookie.userid
  5. if (userId) {
  6. if (!SESSION_DATA[userId]) {
  7. SESSION_DATA[userId] = {}
  8. }
  9. }
  10. else {
  11. needSetCookie=true
  12. userId = `${Date.now()}_${Math.random()}`
  13. SESSION_DATA[userId] = {}
  14. }
  15. req.session = SESSION_DATA[userId]
  16. //设置数据
  17. req.session.username=data.username;
  18. req.session.realName=data.realName;

redis

  • web server最常用的缓存数据库,数据存放在内存中

  • 相比于mysql,访问速度快(内存和硬盘不是一个数量级的)

  • 成本高,可存储的数据量小

  • 安装redishttps://github.com/microsoftarchive/redis/releases

  • 启动redis

    • 打开一个cmd窗口进入redis安装目录redis-server.exe redis.windows.conf
    • 在redis目录下再打开一个cmdredis-cli.exe -h 127.0.0.1 -p 6379

node中使用redis

  • 安装rediscnpm i redis -S
  1. //导入redis模块
  2. const redis=require("redis")
  3. //创建redis客户端 端口对应redis启动时的端口号
  4. const redisClient=redis.createClient(6379,"127.0.0.1")
  5. //监听redis客户端是否发生异常
  6. redisClient.on("error",err=>{
  7. console.log(err)
  8. })
  9. //测试 redis.print设置了这个参数会打印出设置是否成功
  10. //向redis中添加数据
  11. redisClient.set("myname","张三",redis.print)
  12. //获取redis中的数据
  13. redisClient.get("myname",(err,val)=>{
  14. if(err){
  15. return console.log(err)
  16. }
  17. console.log(val)
  18. //退出
  19. redisClient.quit()
  20. })
  • 对获取数据和设置数据的封装 ```javascript function set(key, val) { //测试 redis.print设置了这个参数会打印出设置是否成功 if (typeof val === ‘object’) {
    1. val = JSON.stringify(val)
    } redisClient.set(key, val, redis.print) }

function get(key) { return new Promise((resolve, reject) => { redisClient.get(key, (err, val) => { if (err) { return reject(err) }

  1. if (val == null) {
  2. return resolve(null)
  3. }
  4. try {
  5. resolve(JSON.parse(val))
  6. } catch (error) {
  7. resolve(val)
  8. }
  9. })
  10. })

}

  1. <a name="nginx"></a>
  2. ### nginx
  3. -
  4. [基本使用方式](https://blog.csdn.net/u011418717/article/details/52776090)
  5. -
  6. 高性能的web服务器,开源免费
  7. -
  8. 一般用于做静态服务,负载均衡
  9. -
  10. 反向代理(对客户端不可见的代理,实现前后端跨域访问)
  11. -
  12. 测试配置文件格式是否正确`nginx -t`
  13. -
  14. 启动`start nginx`,重启`nginx -s reload`
  15. -
  16. 停止`nginx -s stop`
  17. -
  18. 配置
  19. ```javascript
  20. //通过server属性配置多个服务器的地址,当一个服务器不能使用,nginx自动检索下一个
  21. upstream local_tomcat {
  22. server localhost:8001;
  23. server localhost:4000;
  24. }
  25. server {
  26. listen 8080;//nginx服务器的端口号
  27. server_name localhost;
  28. location /{
  29. proxy_pass http://localhost:8001;//当访问127.0.0.1:8080/时nginx服务器代理默认跳到http://localhost:8001
  30. #proxy_pass http://local_tomcat =>upstream的使用
  31. }
  32. location /api/{
  33. proxy_pass http://localhost:8000;//当访问127.0.0.1:8080/api/时nginx服务器代理默认跳到http://localhost:8000
  34. proxy_set_header Host $host;//由于访问的地址是localhost:8080/api/...,而实际需要访问的地址是http://localhost:8000/api/...,两个的请求头localhost:8080(localhost:8000)不相同,如果后端设置有请求头限制比如只能访问localhost:8000,那么就会报错,所以设置proxy_set_header Host $host就是为了当在向后端发送请求时,指定请求头为 proxy_pass指定的值
  35. }
  36. }

node操作文件

  • 读取文件
  1. //读取文件的模块
  2. const fs=require("fs")
  3. //拼接文件路径的模块
  4. const path=require("path")//用于拼接路径,由于不能的系统路径不一样,因此使用这个模块,能够保证路径的统一
  5. const filename=path.resolve(__dirname,"data.txt")//获取当前目录下的data.txt文件的路径名
  6. //读取文件内容
  7. //参数1为文件的路径,参数2为回调函数
  8. fs.readFile(filename,(err,data)=>{
  9. if(err){
  10. return console.log(err)
  11. }
  12. console.log(data.toString())
  13. })
  • 写入文件
  1. const fs=require("fs")
  2. const path=require("path")//用于拼接路径,由于不能的系统路径不一样,因此使用这个模块,能够保证路径的统一
  3. const filename=path.resolve(__dirname,"data.txt")//获取当前目录下的data.txt文件的路径名
  4. //写入文件
  5. const content="11111111111111111111111111111111"
  6. const opt={
  7. flag:'a',//追加写入,覆盖用'w'
  8. }
  9. //参数1是写入文件的路径,
  10. //参数2为向文件写入的内容,
  11. //参数3为写入的方式,a表示追加写入,w覆盖写入
  12. //参数4是一个回调函数
  13. fs.writeFile(filename,content,opt,(err)=>{
  14. if(err){
  15. return console.log(err)
  16. }
  17. })
  • 判断文件是否存在
  1. //判断文件是否存在
  2. fs.exists(filename,(exist)=>{
  3. console.log(exist)//文件存在返回true,否则为false
  4. })
  • stream操作文件
  1. const fs = require("fs")
  2. const path = require("path")
  3. //被读取的文件路径
  4. const filename1 = path.resolve(__dirname, "data1.txt")
  5. //写入内容的文件路径
  6. const filename2 = path.resolve(__dirname, "data2.txt")
  7. //读取文件的stream对象
  8. const readStream = fs.createReadStream(filename1);
  9. //写入文件的stream对象
  10. const writeStream = fs.createWriteStream(filename2);
  11. //执行拷贝,通过pipe
  12. readStream.pipe(writeStream);
  13. //拷贝结束
  14. readStream.on("end",(err)=>{
  15. if(err){
  16. console.log(err)
  17. }
  18. })
  • 请求读取文件
    1. const path=require("path")
    2. const fs=require("fs")
    3. const http=require("http")
    4. const filename1 = path.resolve(__dirname, "data1.txt")
    5. const filename2 = path.resolve(__dirname, "data2.txt")
    6. http.createServer((req,res)=>{
    7. if(req.method==="POST"){
    8. let postData="";
    9. req.on("data",chuck=>{
    10. postData=chuck.toString();//json格式的字符串
    11. })
    12. req.on("end",()=>{
    13. postData=JSON.parse(postData)
    14. if(postData.filename==="data1"){
    15. //读取文件的stream对象
    16. const readStream = fs.createReadStream(filename1);
    17. readStream.pipe(res)
    18. }
    19. else{
    20. //读取文件的stream对象
    21. const readStream = fs.createReadStream(filename2);
    22. readStream.pipe(res)
    23. }
    24. })
    25. }
    26. }).listen(8000)
  • node向文件中写日志
    1. const fs=require("fs")
    2. const path=require("path")
    3. //写日志
    4. function writeLog(writeStream,log){
    5. writeStream.write(log+"\n")
    6. }
    7. //生成write Stream
    8. function createWriteStream(fileName){
    9. //日志文件的存储地址
    10. const fullFileName=path.resolve(__dirname,"../","../","logs",fileName)
    11. const writeStream=fs.createWriteStream(fullFileName,{flags:'a'})
    12. return writeStream;
    13. }
    14. //写访问日志
    15. const accessWriteStream=createWriteStream('access.log')
    16. function access(log){
    17. writeLog(accessWriteStream,log)
    18. }
    19. module.exports={
    20. access
    21. }

node中的md5加密

  1. const crypto=require("crypto");
  2. //密匙
  3. const SECRET_KEY="123456"
  4. //md5加密
  5. function md5(content){
  6. let md5=crypto.createHash("md5");//创建一个hash对象,创建hash对象使用的算法是md5
  7. //md5.update(content)使用给定的content更新hash对象的内容,.digest("hex")使用相应的字符编码返回hash值
  8. return md5.update(content).digest("hex")
  9. }
  10. //加密函数
  11. function getPassword(password){
  12. const str=`password=${password}&key=${SECRET_KEY}`
  13. return md5(str)
  14. }
  15. console.log(getPassword(123))

node中连接数据库

  • 安装mysql模块cnpm i mysql -S

  • mysql模块的简介

    1. //导入mysql模块
    2. const mysql=require("mysql")
    3. //创建数据库连接对象
    4. const conn=mysql.createConnection({
    5. host:"localtion",
    6. host:"localhost",//数据库连接的ip地址
    7. user:"root",//连接数据库的用户名
    8. password:"root",//连接数据库的密码
    9. port:"3306",//数据库的端口号
    10. database:"myblog"//数据库的名称
    11. })
    12. //开始连接数据库
    13. conn.connect((err)=>{
    14. if(err)console.log(err)
    15. })
    16. //封装的一个进行增删改查的函数
    17. function exec(sql){
    18. return new Promise((resolve,reject)=>{
    19. con.query(sql,(err,result)=>{
    20. if(err){
    21. return reject(err)
    22. }
    23. resolve(result)
    24. })
    25. })
    26. }

express框架

安装express

  1. cnpm i express-generator -g //安装express脚手架
  2. express express-test //创建express应用
  3. npm start //运行应用

中间件

  • 使用app.use()注册中间件
  • next()上一个中间件触发下一个中间件
  1. const express = require('express');
  2. const cookieParser = require('cookie-parser');
  3. const app=express()
  4. //处理表单提交数据,将处理后的数据挂载到req.body中
  5. app.use(express.urlencoded({ extended: false }))
  6. //处理json格式的数据
  7. app.use(express.json())
  8. //处理cookie
  9. app.use(cookieParser())
  10. //创建一个路由
  11. const router=express.Router();
  12. //注册路由
  13. const blogRouter = require('./routes/blog');
  14. app.use('/api/blog', blogRouter);
  15. //通过express-session处理session数据
  16. //安装 cnpm i express-session -S
  17. //注册
  18. const session =require("express-session")
  19. var cookieParser = require('cookie-parser');
  20. app.use(cookieParser());
  21. app.use(session({
  22. secret:"qwe",
  23. cookie:{
  24. path:"/",//任意路径都能访问
  25. httpOnly:true,//是否允许修改
  26. maxAge:24*60*60*1000//过期时间
  27. }
  28. }))
  29. //获取session
  30. req.session
  • 路由 ```javascript var express = require(‘express’); var router = express.Router();

router.get(‘/list’, function (req, res, next) { res.json({

  1. })

});

router.get(“/detail”,(req,res,next)=>{

})

module.exports = router;

  1. <a name="7b79f329"></a>
  2. #### 使用redis
  3. ```javascript
  4. //安装redis connect-redis模块
  5. //cnpm i redis connect-redis -S
  6. //redis的配置
  7. REDIS_CONF={
  8. port:6379,
  9. host:"127.0.0.1"
  10. }
  11. //创建redis客户端
  12. const redis = require("redis")
  13. const { REDIS_CONF } = require("../config/db")
  14. //创建客户端
  15. const redisClient = redis.createClient(REDIS_CONF.port, REDIS_CONF.host)
  16. //监听redis客户端是否产生异常
  17. redisClient.on("error", err => {
  18. console.log(err)
  19. })
  20. module.exports=redisClient
  21. //将redis与session进行关联
  22. const session =require("express-session")
  23. const RedisStore=require("connect-redis")(session)
  24. const redisClient=require("./db/redis")
  25. const sessionStore=new RedisStore({
  26. client:redisClient
  27. })
  28. app.use(session({
  29. secret:"qwe",
  30. cookie:{
  31. path:"/",//任意路径都能访问
  32. httpOnly:true,//是否允许修改
  33. maxAge:24*60*60*1000//过期时间
  34. },
  35. store:sessionStore
  36. }))

日志

  • 使用模块morgan完成日志的输出 ```javascript //morgan的简介https://github.com/expressjs/morgan const logger = require(‘morgan’); / 环境类型 “scripts”: { “start”: “node ./bin/www”, “dev”: “cross-env NODE_ENV=dev nodemon ./bin/www.js”, “prd”: “cross-env NODE_ENV=production nodemon ./bin/www.js” } /

const ENV=process.env.NODE_ENV//获取环境类型 if(ENV!==”production”){ //开发环境/测试环境 app.use(logger(‘dev’)); } else{ //线上环境 const logFilename=path.join(__dirname,”logs”,”access.log”)//拼接文件路径 const writeStream=fs.createWriteStream(logFilename,{ flags:”a” })//创建一个文件日志写入流 app.use(logger(“combined”,{ stream:writeStream//将日志写文件 })) }

  1. <a name="1b2326dc"></a>
  2. #### express实现原理
  3. ```javascript
  4. const http=require("http");
  5. const slice=Array.prototype.slice;
  6. class LikeExpress{
  7. constructor(){
  8. //存放中间件的列表
  9. this.router={
  10. all:[],//存放使用use注册的中间件
  11. get:[],//存放使用get注册的中间件
  12. post:[]//存放使用post注册的中间件
  13. }
  14. }
  15. register(path){
  16. const info={}
  17. if(typeof path==="string"){
  18. info.path=path;
  19. //从第二个函数开始,转换为数组,存入stack中
  20. info.stack=slice.call(arguments,1) //数组
  21. //arguments是类数组对象,有一些数组中的方法它们是没有的
  22. }
  23. else{
  24. info.path="/"
  25. //从第二个函数开始,转换为数组,存入stack中
  26. info.stack=slice.call(arguments,0) //数组
  27. }
  28. return info;
  29. }
  30. use(){
  31. const info=this.register.apply(this,arguments)
  32. this.router.all.push(info)
  33. }
  34. get(){
  35. const info=this.register.apply(this,arguments)
  36. this.router.get.push(info)
  37. }
  38. post(){
  39. const info=this.register.apply(this,arguments)
  40. this.router.post.push(info)
  41. }
  42. match(method,url){
  43. let stack=[]
  44. if(url==='/favicon.ico'){
  45. return stack;
  46. }
  47. //获取routes
  48. let curRoutes=[]
  49. curRoutes=curRoutes.concat(this.router.all)
  50. curRoutes=curRoutes.concat(this.router[method])
  51. curRoutes.forEach(item=>{
  52. if(url.indexOf(item.path)===0){
  53. stack=stack.concat(item.stack)
  54. }
  55. })
  56. return stack;
  57. }
  58. //核心的next机制
  59. handle(req,res,stack){
  60. const next=()=>{
  61. //第一个匹配的中间件
  62. const middleware=stack.shift()
  63. if(middleware){
  64. //执行中间件函数
  65. middleware(req,res,next)
  66. }
  67. }
  68. next()
  69. }
  70. callback(){
  71. return (req,res)=>{
  72. res.json=(data)=>{
  73. res.setHeader("Content-type","application/json")
  74. res.end(
  75. JSON.stringify(data)
  76. )
  77. }
  78. const url=req.url
  79. const method=req.method.toLowerCase()
  80. const resultList=this.match(method,url)
  81. this.handle(req,res,resultList)
  82. }
  83. }
  84. listen(...args){
  85. const server=http.createServer(this.callback())
  86. server.listen(...args)
  87. }
  88. }
  89. //工厂函数
  90. module.exports=()=>{
  91. return new LikeExpress();
  92. }
  93. //流程前端发送请求->listen->callback->match->handle

koa2框架

  • express中间件是异步回调,koa2原生支持async/await
  • 简介

安装

  1. koa2的脚手架 npm i koa-generator -g
  2. 初始化环境 Koa2 koa2-test(文件架名字)
  3. 启动 npm i & npm run dev

中间件

  1. const Koa = require('koa')
  2. const app = new Koa()
  3. //出路json格式数据
  4. const json = require('koa-json')
  5. //错误处理
  6. const onerror = require('koa-onerror')
  7. //处理表单提交的数据
  8. const bodyparser = require('koa-bodyparser')
  9. // 日志美化
  10. const logger = require('koa-logger')
  11. //引入路由
  12. const blog=require("./routes/blog")
  13. // error handler
  14. onerror(app)
  15. // 处理表单提交
  16. app.use(bodyparser({
  17. enableTypes:['json', 'form', 'text']
  18. }))
  19. //处理json格式数据
  20. app.use(json())
  21. //处理日志
  22. app.use(logger())
  23. // 日志处理
  24. app.use(async (ctx, next) => {
  25. const start = new Date()
  26. await next()
  27. const ms = new Date() - start
  28. console.log(`${ctx.method} ${ctx.url} - ${ms}ms`)
  29. })
  30. // 路由注册
  31. app.use(blog.routes(), blog.allowedMethods())
  32. // 错误处理
  33. app.on('error', (err, ctx) => {
  34. console.error('server error', err, ctx)
  35. });
  36. module.exports = app
  • 路由 ```javascript const router = require(‘koa-router’)()

router.prefix(“/api/blog”);//设置请求路径的前缀

router.get(‘/list’, function (ctx, next) { const query = ctx.query;//相等于req.query返回查询字符串 ctx.body = {//相当于 error: 0, query, data: [“获取博客列表”] } })

module.exports = router

  1. <a name="75106630"></a>
  2. #### koa中的session
  3. -
  4. 基于koa-generic-session和koa-redis
  5. ```javascript
  6. //安装插件 cnpm i koa-generic-session koa-redis redis -S
  7. //处理session
  8. const session =require("koa-generic-session")
  9. //处理redis,这个模块依赖redis
  10. const redisStore=require("koa-redis")
  11. // 设置签名的密钥
  12. app.keys=["123"]
  13. //设置session,并将session与redis关联
  14. app.use(session({
  15. cookie:{
  16. path:"/",//所有的路由都能使用
  17. httpOnly:true,//不允许前端修改
  18. maxAge:24*60*60*1000//有效时间
  19. },
  20. store:redisStore({
  21. all:'127.0.0.1:6379'
  22. })//配置redis
  23. }))

日志

  1. //安装兼容模块(morgan是express中的模块)cnpm i koa-morgan -S
  2. /*
  3. 环境类型
  4. "scripts": {
  5. "start": "node ./bin/www",
  6. "dev": "cross-env NODE_ENV=dev nodemon ./bin/www.js",
  7. "prd": "cross-env NODE_ENV=production nodemon ./bin/www.js"
  8. }
  9. */
  10. const path=require("path")
  11. const fs=require("fs")
  12. const morgan=require("koa-morgan")
  13. const ENV=process.env.NODE_ENV
  14. if(ENV!=="production"){
  15. //开发环境
  16. app.use(morgan('dev'));
  17. }
  18. else{
  19. //线上环境
  20. const logFilename=path.join(__dirname,"logs","access.log")
  21. const writeStream=fs.createWriteStream(logFilename,{
  22. flags:"a"
  23. })
  24. app.use(morgan("combined",{
  25. stream:writeStream
  26. }))
  27. }

koa2实现原理

  1. const http=require("http")
  2. //组合中间件
  3. function compose(middlewareList){
  4. return function(ctx){
  5. //中间的调用
  6. function dispatch(i){
  7. const fn=middlewareList[i]
  8. try{
  9. return Promise.resolve(
  10. fn(ctx,dispatch.bind(null,i+1))
  11. )
  12. }catch(err){
  13. return Promise.reject(
  14. err
  15. )
  16. }
  17. }
  18. return dispatch(0)
  19. }
  20. }
  21. class LikeKoa2{
  22. constructor(){
  23. this.middlewareList=[]
  24. }
  25. use(fn){
  26. this.middlewareList.push(fn)
  27. return this
  28. }
  29. createContext(req,res){
  30. const ctx={
  31. req,res
  32. }
  33. return Object.assign(ctx,req,res)
  34. }
  35. handleRequest(ctx,fn){
  36. return fn(ctx)
  37. }
  38. callback(){
  39. const fn=compose(this.middlewareList)
  40. return (req,res)=>{
  41. const ctx=this.createContext(req,res)
  42. return this.handleRequest(ctx,fn)
  43. }
  44. }
  45. listen(...args){
  46. const server=http.createServer(this.callback())
  47. server.listen(...args)
  48. }
  49. }
  50. module.exports=LikeKoa2