NodeJS,HTTP模块,模块化开发,通过解析路由,实现MVC框架

背景说明

HTTP模块一个轻量的,基于异步I/O的,以及事件驱动的 Web 服务器。

url模块,用于生成和解析URL,使用前,先加载。

querystring模块,http请求数据进行解析,提供4个方法:1、querystring.parse,将一个字符串反序列化为一个对象;2、querystring.stringify,将一个对象序列化成一个字符串,与querystring.parse是相对的;3、querystring.escape,escape可使传入的字符串进行编码;4、querystring.unescape,unescape方法可将含有%的字符串进行解码。

util模块,promisify(),Node.js内置的util模块的promisify()方法,将基于回调的函数转换为基于Promise的函数。可以将Promise链和async/await与基于回调的API结合使用。

工程结构

工程
  │  app.js
  │  package.json
  │
  ├─data
  │      user.json
  │
  ├─router
  │      index.js
  │
  ├─static
  │      login.html

工程代码

app.js

const http = require('http');
const url = require('url');
const router = require('./router/index');

const app = http.createServer((req, res) => {
  // 当前请求方法
  const method = req.method.toUpperCase();
  console.log("当前请求方法:" + method);
  // 当前请求路径
  const { pathname } = url.parse(req.url);
  console.log("当前请求方法:" + pathname);
  // GET处理
  if (method === 'GET') {
    switch (pathname) {
      case '/':
        router.index(req, res)
        break;
      case '/index':
        router.index(req, res)
        break;
      case '/json':
        router.json(req, res)
        break;
      case '/query':
        router.query(req, res)
        break;
    }
  }
  // POST处理
  if (method === 'POST') {
    switch (pathname) {
      case '/login':
        router.login(req, res)
        break;
      case '/register':
        router.register(req, res)
        break;
    }
  }
});

app.listen(3000, () => {
  console.log('服务3000已启动.')
});

package.json

{
  "name": "demo",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
	"start":"node app.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

router/index.js

const url = require('url');
const path = require('path');
const fs = require('fs');
const qs = require('querystring');
const { promisify } = require('util');
const readFile = promisify(fs.readFile);
const writeFile = promisify(fs.writeFile);

module.exports = {
  // 首页
  index(req, res) {
    let appDir = path.dirname(require.main.filename);
    console.log("appDir=" + appDir + ", __dirname=" + __dirname);
    //读取静态文件并生成流
    fs.readFile(appDir + '/static/login.html', function (err, data) {
      if (err) {
        res.writeHead(404, { 'Content-Type': 'text/html;charset=utf-8' });
        res.write("页面不存在!404");
        res.end();
      } else {
        res.writeHead(200, { 'Content-Type': 'text/html;charset=utf-8' });
        res.write(data.toString());
        res.end();
      }
    });
  },
  json(req, res) {
    res.status = 200;
    res.setHeader('Content-Type', 'application/json');
    // res.writeHead(200, { 'Content-Type': 'application/json;charset=utf-8' });
    res.end(JSON.stringify({
      msg: 'json'
    }));
  },
  // 查询
  query(req, res) {
    const { query } = url.parse(req.url, true);
    res.status = 200
    res.setHeader('Content-Type', 'application/json')
    res.end(JSON.stringify(query || {}))
  },
  // 登录页面
  login(req, res) {
    let array = [];
    req.on('data', (chunk) => {
      array.push(chunk);
    })
    req.on('end', async () => {
      let params = Buffer.concat(array).toString();
      params = qs.unescape(params);
      console.log("params>>>>>>" + params);
      let paramArray = params.split("&");
      let loginData = {};
      if (paramArray && paramArray.length > 0) {
        paramArray.forEach((item, index) => {
          let strs = item.split("=");
          if (strs.length >= 2) {
            loginData[strs[0]] = strs[1];
          }
        });
      }
      console.log("loginData>>>>>>" + loginData);
      try {
        const appDir = path.dirname(require.main.filename);
        const jsonPath = appDir + "/data/user.json";
        let jsonData = await readFile(jsonPath, { encoding: 'utf8' });
        console.log("jsonData>>>>>>" + jsonData);
        console.log("jsonData>>>>>>" + JSON.parse(jsonData || '[]'));
        let result = JSON.parse(jsonData || '[]').some(item => {
          console.log("loginData.username=" + loginData.username);
          console.log("item.username=" + item.username);
          console.log("loginData.password=" + loginData.password);
          console.log("item.password=" + item.password);
          return item.username === loginData.username && item.password === loginData.password
        })
        if (result) {
          res.status = 200;
          res.setHeader('Content-Type', 'application/json')
          res.end(JSON.stringify({
            msg: '登录成功'
          }))
        } else {
          res.status = 400;
          res.setHeader('Content-Type', 'application/json')
          res.end(JSON.stringify({
            msg: '登录失败'
          }))
        }
      } catch (e) {
        res.status = 500;
        res.setHeader('Content-Type', 'application/json')
        res.end(JSON.stringify({
          msg: '登录错误',
          err: e.message
        }))
      }
    })
  },
  register(req, res) {
    let array = [];
    req.on('data', (chunk) => {
      array.push(chunk);
    })
    req.on('end', async () => {
      console.log("array.length", array.length);
      console.log("array", array);
      let params = Buffer.concat(array).toString();
      // params username=%E7%94%A8%E6%88%B7&password=mima
      console.log("params", params);
      // params username=用户&password=mima
      params = qs.unescape(params)
      console.log("params", params);
      // 
      let paramArray = params.split("&");
      let objectArray = [];
      if (paramArray && paramArray.length > 0) {
        paramArray.forEach((item, index) => {
          let strs = item.split("=");
          if (strs.length >= 2) {
            let obj = {};
            obj[strs[0]] = strs[1];
            objectArray.push(obj);
          }
        });
      }
      console.log("objectArray", objectArray);
      // 注册成功
      res.status = 200;
      res.setHeader('Content-Type', 'application/json')
      res.end(JSON.stringify({
        msg: '注册成功',
        data: objectArray
      }));
    });
  }
}

static/login.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>用户登录</title>
  <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
  <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.6.1/css/bootstrap.min.css" rel="stylesheet">
</head>

<body>
  <div class="container " style="width:600px;">
    <span>
      <h1>用户登录</h1>
    </span>
    <form method="post" action="/login">
      <div class="form-group">
        <label for="username">用户名:</label>
        <input id="username" name="username" type="text" class="form-control" value="" />
      </div>
      <div class="form-group">
        <label for="password">密码:</label>
        <input id="password" name="password" type="password" class="form-control" value="" />
      </div>
      <button type="reset" class="btn btn-secondary">取消</button>
      <button type="submit" class="btn btn-danger">登录</button>
    </form>
  </div>
</body>

</html>

data/user.json

[
	{
	 	"id": "1",
	 	"username": "admin",
	 	"password": "admin123",
	 	"mobile": null,
	 	"email": null,
	 	"jobNumber": null,
	 	"nickname": null,
	 	"portraitId": null,
	 	"portraitAddress": null,
	 	"workPost": null,
	 	"workRole": null,
	 	"sorted": 1,
	 	"status": 1,
	 	"type": "1",
	 	"name": "用户",
	 	"idNumber": null,
	 	"remarks": null,
	 	"lockType": 1,
	 	"startTime": null,
	 	"expireTime": null,
	 	"orgId": "1501744401741774848",
	 	"orgName": "所属机构",
	 	"deptId": "1526411740659580928",
	 	"deptName": "所属部门",
	 	"orgLevel": 3,
	 	"orgTree": "1497055230288723968,1501744401741774848,1526411740659580928",
	 	"domainId": "1497055230288723968",
	 	"roleId": null,
	 	"hisUserId": null,
	 	"version": 0,
	 	"createUid": 0,
	 	"belongOrg": {
	 		"id": "1501744401741774848",
	 		"name": "所属机构",
	 		"code": "S2333",
	 		"type": 1,
	 		"status": 1,
	 		"parentId": "1497055230288723968",
	 		"treeLevel": 2,
	 		"parentFullPath": "1497055230288723968",
	 		"sorted": 1,
	 		"remarks": "",
	 		"belongOrgId": "1497055230288723968",
	 		"domainId": "1497055230288723968",
	 		"logicalDeleted": 0,
	 		"createUid": "1",
	 		"createUser": "super",
	 		"createTime": "2022-03-10T02:19:01.000+00:00",
	 		"modifiedUser": null,
	 		"modifiedTime": null,
	 		"deletedUser": null,
	 		"deletedTime": null,
	 		"children": null,
	 		"parentOrg": null,
	 		"fullPath": "1497055230288723968,1501744401741774848"
	 	},
	 	"belongDept": {
	 		"id": "1526411740659580928",
	 		"name": "所属部门",
	 		"code": "B121212",
	 		"type": 4,
	 		"status": 1,
	 		"parentId": "1501744401741774848",
	 		"treeLevel": 3,
	 		"parentFullPath": "1497055230288723968,1501744401741774848",
	 		"sorted": 2,
	 		"remarks": "",
	 		"belongOrgId": "1501744401741774848",
	 		"domainId": "1497055230288723968",
	 		"logicalDeleted": 0,
	 		"createUid": "1",
	 		"createUser": "super",
	 		"createTime": "2022-05-17T03:58:13.000+00:00",
	 		"modifiedUser": null,
	 		"modifiedTime": null,
	 		"deletedUser": null,
	 		"deletedTime": null,
	 		"children": null,
	 		"parentOrg": null,
	 		"fullPath": "1497055230288723968,1501744401741774848,1526411740659580928"
	 	}
	}
]

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注