node.js ------封装webserver业务逻辑梳理

webserver业务逻辑梳理

  • 创建一个webserver.js文件
  • 在与webserver.js文件同级创建一个public文件夹,在public文件夹下的static文件夹下创建js、css、images文件夹
    – 在public创建一个index.html文件
  • 在与webserver.js文件同级创建config.js文件
    – 在config文件里创建三个变量wwwroot、indexArr、errorOut,
    – 找到网站根目录并赋值给wwwroot,变量indexArr,用来存放入口文件名(不加/的文件名),errorOut变量用来存放一个对象{403:,404:,500:}每个键对应的值就是对应的错误页面相对于电脑根目录的相对地址.
    – 将对象{wwwroot,indexArr,errorOut}暴露出去
    – webserver.js文件里面引入config.js文件
    – 创建一个router文件
    创建一个对象router{自定义的路径名:js文件路径@js文件里的方法名}
    暴露出router对象
  • 在webserver.js同级创建一个controller文件夹,里面存放一个test.js
    – 在test.js写两个函数,并把函数暴露出来
  • 在与webserver.js文件同级创建一个errorpages文件夹存放错误页面
    – 在errorpages文件夹创建一个404.html文件
    – 在errorpages文件夹创建一个403.html文件
    – 在errorpages文件夹创建一个500.html文件

webserver.js文件内容:

  • 引入http模块,将其结果赋值给一个变量
  • 引入fs模块,将其结果赋值给一个变量
  • 引入querystring模块,将其结果赋值给一个变量
  • 引入mime模块,将其结果赋值给一个变量(要记得npm install --save mime模块)
  • 引入config文件,将声明一个对象,对象里面的几个变量(解构)对应config暴露出去的名字.
  • 引入router文件并赋值给变量Router
  • 声明两个全局变量,request、response并赋值为null(为了不用传参,并且这两个变量极其特殊)
  • 创建一个httpserver对象
  • 监听httpserver的request事件
    – 当有请求时,把实参请求对象赋值给全局变量request
    – 为request创建一个params键并赋值一个对象{get:"",post:""}
    – 通过“?”切割请求地址,得到的后半部分赋值给request的params的get,并将其通过querystring解析成一个对象
    – 创建监听请求对象的输入流(data)事件,这个事件的句柄里面的形参为chuck,用request的params的post接收一个个chuck,并且拼接起来
    – 创建监听请求对象的end,这个事件句柄如下:
    把request的params的post的内容通过querystring解析成一个对象
    声明一个变量url接收req.url里面的地址部分(通过“?”切割请求的地址的0下标)
    调用找函数,将变量url作为实参传入找函数,用一个变量pathObj接收找函数的返回值,
    调用读函数,向读函数传入的参数是pathObj里面的完整路径、函数名,声明变量dataObj接收读函数的返回值
    调用返函数,向返函数里面传入pathObj里面的状态码、dataObj里的读取的数据和文件类型
  • httpserver监听一个端口

封装找函数

  • 找函数的意义是查找文件地址以及相应的状态码
  • 找函数的参数是地址
  • 找函数的返回值是一个对象,对象{完整路径,状态码}
    声明一个对象用来存放{路径和状态码}
    首先判断路由里面是否有该请求的地址的键,如果有就获取该键的值,切割该值得到一个文件地址赋值前面声明的对象,并且给对象创建一个方法名的键存放切割后得到的一个函数名,并且状态 码为200,并作为函数的返回值
    声明一个真实路径,把wwwroot+形参赋值给真实路径
    判断真实路径是否存在,如果存在就返回对象{真实路径和状态码200},不存在就返回{404对应的路径和状态码404}
    判断路径是否为文件夹或者文件,如果不是文件,就调用找入口文件函数,路径作为参数,返回 找入口文件的返回值
    判断该文件是否有读的权限,如果没有就返回对象{403对应的路径和状态码403}
    如果以上if都通过,则返回一个正常的{拼接后路径和状态码200}

封装读函数

  • 函数的意义是读取文件类型,解析文件内容
  • 读函数的参数是路径、函数名
  • 读函数的返回值是对象{读取的数据,文件类型}
    声明一个对象{data,文件类型}
    根据传入的地址,用split切割.生成一个新数组
    将新数组的后半部分赋值给一个变量,此变量即为后缀名
    进行判断(后缀名为js且request的params的get的api存在且存在函数名)
  1. 足条件则解析js文件,并执行对应的函数,函数传一个request,将函数返回结果赋值给对象里面的data
  2. 清除解析js文件的缓存
  3. 文件类型解析为json,并赋值给对象里面的文件类型
  4. 返回对象{data,文件类型}
  • 使用mime模块判断变量是什么文件类型
  • 读取传入的地址所对应的文件内容
  • 返回对象{data,文件类型}

封装返函数

  • 返函数的参数是状态码、读取的数据、文件类型
  • 返函数的意义:将数据发送给客户端
    – 调用response下的writeHead函数,把状态码、文件类型传进去
    – 调用response下的write函数,把data传进去
    – 调用response下的end函数

入口文件函数

  • 判断传入的地址的最后一位是否为"/",如果不为"/",拼接上"/".
  • 遍历入口文件(indexArr)数组,数组元素依次拼接传过来的路径的,判断文件是否存在,只要有一个存在就返回{拼接后的路径和状态码200},如果不存在{403对应的路径和状态码403}
//引入模块
const http = require("http");
const fs = require("fs");
const mime = require("mime");
const querystring = require('querystring');
const router = require('./router.js');

//引入配置文件
const { root, errorpages, indexArr } = require("./config.js");//声明的变量名和对象的键名一致
let server = http.createServer()
let request = null;
let response = null;

server.on("request", function (req, res) {
    request = req;
    response = res;
    request.params = { get: "", post: "" };
    //post参数的获取:
    req.on("data", function (chunk) {
        request.params.post += chunk;
    })
    req.on("end", function () {
        // 解析参数
        request.params.get = querystring.parse(req.url.split("?")[1]);
        request.params.post = querystring.parse(request.params.post);
        //找,返回查找文件和状态码
        let pathObj = findPath(req.url.split("?")[0]);
        // console.log(pathObj)
        //读
        let contentObj = readFile(pathObj);
        // console.log(contentObj)
        //返
        writeFile(contentObj, pathObj.code);
    
    })
})

//找函数
function findPath(url) {
    let pathObj = { path: "", code: 200 };
    // 找路由
    if (router[url]) {
        pathObj.path = router[url].split("@")[0];
        pathObj.funName = router[url].split("@")[1];
        pathObj.code = 200;
        return pathObj;
    }
    root[root.length - 1] == "/"
        ? pathObj.path = root.slice(0, root.length - 1) + url
        : pathObj.path = root + url;
    // fs.exists(path,callback)来检查目录文件是否存在,fs.existsSync:以同步的方法检测目录是否存在。如果目录存在返回 true ,如果目录不存在 返回false
    if (!fs.existsSync(pathObj.path)) {
        return { path: errorpages[404], code: 404 }
    }
    //判断该文件类型是否是一个文件,如果不是文件,则在这个目录下面查找
    if (!fs.statSync(pathObj.path).isFile()) {
        return exportfile(pathObj.path);
    }
    //判断是否有读取文件的权限, //如果没有返回403;
    if (!isaccess(pathObj.path)) {
        return { path: errorpages[403], code: 403 }
    }
    return pathObj;
}

//多个入口文件
function exportfile(path) {
    path = path[path.length - 1] == "/" ? path : path + "/"
    for (let i = 0; i < indexArr.length; i++) {
        let pathObj = { path: path + indexArr[i], code: 200 }
        if (fs.existsSync(pathObj.path)) {//如果目录不存在
            return pathObj;
        }
    }
    return { path: errorpages[403], code: 403 }
}

//判断是否有读取文件的权限
function isaccess(url) {
    try {
        fs.accessSync(url, fs.constants.R_OK);
        return true;
    } catch (err) {
        return false;
    }
}

//读文件要使用了mine模块同步方式读取文件
function readFile(pathObj) {
    let resObj = { data: "", fileType: "" };
    let urlTempArr = pathObj.path.split(".");
    let type = urlTempArr[urlTempArr.length - 1];
    //api请求
    if (type == "js" && request.params.get.api && pathObj.funName) {
        resObj.data = require(pathObj.path)[pathObj.funName](request);
        delete require.cache[pathObj.path];
        resObj.fileType = mime.getType("JSON")
        return resObj;
    }
    resObj.fileType = mime.getType(type);
    resObj.data = fs.readFileSync(pathObj.path);//同步
    return resObj;
}

//返函数,content文件内容,res:响应对象,writeHead 的返回值是res本身
// let pathObj = { path: "", code: ""};
// let contentObj = readFile(pathObj, funName)
// writeFile(contentObj, resObj, pathObj.code);
function writeFile(contentObj, code) {
    response.writeHead(code, {
        'Content-Type': contentObj.fileType,
        'Access-Control-Allow-Origin': '*',  //支持全域名访问,不安全,部署后需要固定限制为客户端网址
        'Access-Control-Allow-Methods': 'POST,GET,OPTIONS,DELETE',//支持的http 动作
        'Access-Control-Allow-Headers': 'x-requested-with,content-type' //响应头 请按照自己需求添加。
    })
    response.write(contentObj.data);//文件内容
    response.end();

}


// server.listen(8080, function () {
//     console.log('服务器运行在http://192.168.1.22:8080/')
// });

module.exports = server;
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值