Node.js必知必会学习笔记(第五章)

305 阅读3分钟

node.js封装一个类似express框架

express基础使用方法:

详情可参考官网https://www.npmjs.com/package/express

const express = require('express')
const app = express()
 
app.get('/', function (req, res) {
  res.send('Hello World')
})
 
app.listen(3000)

node.js封装一个类似express框架

实现的基本思路---思路案例一:

/**
 * 最终目标是以这样的方式配置路由
 * app.get('/',function(req,res){
 *      res.send('hello world')
 * })
 */

思路转变:

//函数也是对象,那么就能不断的往app上添加属性
let app=function(){
    console.log('app方法')
}

app.get=function(){
    console.log('get方法')
}

app.post=function(){
    console.log('post方法')
}

//调用
app.get() //'get方法'
app.post() //'post方法'
app() //'app方法'

思路转变:

//定义一个空对象
let G={};


//函数也是对象,那么就能不断的往app上添加属性
let app=function(req,res){
    //如果存在G['/']则去执行该属性对应的方法
    if(G['/']){
        G['/'](req,res)  //执行方法
    }
}


app.get=function(str,cb){
    //注册方法
    G[str]=cb;

    /**
     * 等价于---给对象G上添加属性和属性值
     * 注册方法
     * G['/']=function(req,res){
            console.log('执行login方法')
        }       
     */
}

//调用---通过这种方法配置路由
//---注册并执行方法
app.get('/',function(req,res){
    console.log('执行login方法')
})  //执行login方法

该构建的目录结构为:

下面是module/router.js的页面代码

这是作为第三方模块被入口文件express.js引入

const url=require('url')
const path=require('path')
const fs=require('fs')

//扩展res.send方法

function changeRes(res){
    res.send=(data)=>{
        res.writeHead(200, {'Content-Type': 'text/html;charset="utf-8"'});
        res.end(data);
    }

    /*
        function send(data){
            res.writeHead(200, {'Content-Type': 'text/html;charset="utf-8"'});
            res.end(data);
        }
    */
}

//根据文件后缀名获取content-type的所需值
//封装为一个私有方法--不需要暴露
let getFileMine=function(extname){
    var data=fs.readFileSync('./data/mime.json') //同步方法拿到数据

    let mimeObj=JSON.parse(data.toString());

    return mimeObj[extname]
}

//构建静态web服务器的方法
let initStatic=function(request,response,staticPath){


//1.获得pathname--例如/index.html
let pathname=url.parse(request.url).pathname;

pathname=pathname=='/'?'/index.html':pathname

//2.可以获取后缀名
let extname=path.extname(pathname) 

//3.通过fs模块读取文件
try {
  //根据pathname(通过输入的url获取)判断指定的文件(例如./static/login.html)存不存在
  var data=fs.readFileSync('./'+staticPath+pathname)

  //存在的话
  if(data){
      let mime=getFileMine(extname)
      response.writeHead(200, {'Content-Type': 'text/html;charset="utf-8"'});
      response.end(data);  //不加载css样式
  }
} catch (error) {
  console.log('error', 'error')
}
}

//为了更安全再把它放在server函数里

let server=()=>{
	 let G={
        _get:{},
        _post:{},
         //默认的静态web目录
        staticPath:'static' 
    };
    
//函数也是对象
let app=function(req,res){
//扩展res的方法
changeRes(res);

//配置静态web服务
initStatic(req,res,G.staticPath)


//http://127.0.0.1:3000/news  --->/news
let pathname=url.parse(req.url).pathname
//获取请求类型
let method=req.method.toLowerCase();
//

if(G['_'+method][pathname]){
    if(method=='get'){
        // G['_'+method][pathname](req,res) 
        G._get[pathname](req,res)  //执行方法
    }else{
        //获取post的数据把它绑定到req.body里面
        let postData='';
        req.on('data',(chunk)=>{
            postData+=chunk;
        })
        req.on('end',()=>{
            console.log(postData)
            // res.end(postData)
            req.body=postData
            //请求完成之后执行方法
            G._post[pathname](req,res)  
        })
    }
}else{
    res.writeHead(404, {'Content-Type': 'text/plain'});
    res.end('opps');
}
}
    
    
    
app.get=function(str,cb){
    
    //注册方法
    G._get[str]=cb;

/**
* 执行了app.get方法等价于在注册了G._get对象上注册了方法
* G._get['/']=function(req,res){
res.send('hello world')
}       
*/


/**
* 
*  G['/login']=function(req,res){
*       res.writeHead(200, {'Content-Type': 'text/plain'});
*      res.end('Hello World www');
*   };
* 
*/

}
}


    //配置post请求
    app.post=function(str,cb){
        G._post[str]=cb;

        // G['/login']=function(req,res){
        //     res.writeHead(200, {'Content-Type': 'text/plain'});
        //     res.end('Hello World www');
        // };
    }
    
  // 静态web服务目录
  app.static=function(staticPath){
      G.staticPath=staticPath;
  }
    
    
     //等价于暴露app
    return app;
    
    //等价于暴露app
module.exports=server();

下面是express.js的页面代码

var http = require('http');
var app=require('./module/router');
const ejs=require('ejs');

/*
http.createServer(function (request, response) {
    
}).listen(3000);
*/


//一请求就触发app方法---注册web服务
http.createServer(app).listen(3020);
//配置web静态目录
app.static('static')
//配置路由---注册
app.get('/login',function(req,res){
    // res.writeHead(200, {'Content-Type': 'text/plain'});
    // res.end('Hello World');

    ejs.renderFile('./view/form.ejs',{},(err,data)=>{
        res.writeHead(200, {'Content-Type': 'text/html;charset="utf-8"'});
        res.end(data);
    })
})

app.get('/',function(req,res){
    
    res.send('hello sssss')
    // res.writeHead(200, {'Content-Type': 'text/html;charset="utf-8"'});
    // res.end('Hello World www');
})

app.post('/doLogin',function(req,res){
    console.log(req.body)
    
    res.send(req.body)
    // res.writeHead(200, {'Content-Type': 'text/plain'});
    // res.end(req.body);
})

前后端交互一

  • 利用nodejs模拟服务器端
  • 实现的依赖有:
const Koa = require("koa");
//静态资源托管
const static = require("koa-static");
//动态路由搭建
const Router = require("koa-router");


//通过ctx.request.body来获取post请求提交过来的数据
const koaBody = require("koa-body");
const fs = require("fs");

//文本JSON格式数据-自动转为对象
const usersData = require("./data/users.json");
/* userData的对象数据
[{
    "id":1,
    "username":"张三",
    "pwd":123
},{
    "id":1,
    "username":"李四",
    "pwd":123
}]
*/


let app = new Koa();


//托管静态资源--托管static目录下的静态资源
app.use(static(__dirname+"/static"));


//每一个请求都用到了此中间件(有点性能浪费)
app.use(koaBody({
    multipart:true  //允许接收文件
}));


//实例化Router
let router = new Router();
//测试动态路由
router.get("/",(ctx,next)=>{
    ctx.body = "hello";
})

//启动
app.use(router.routes());
app.listen(8888);