背景说明
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" } } ]