- 原生node封装一个简易的服务器, 把前面几天的知识揉和起来做一个服务器
- 基础实现, 首页访问, 静态资源服务器, 特定接口封装, 404
app.js
服务器入口文件 app.js node app.js即可启动服务器
js
复制代码
const { start } = require('./modules/server');
start();
require_modules.js
整合模块导出
js
复制代码
const url = require('url');
const path = require('path');
const http = require('http');
const querystring = require('querystring');
const fs = require('fs');
const multiparty = require('multiparty');
module.exports = {
url,
path,
http,
querystring,
fs,
multiparty
};
server.js
server 启动模块
js
复制代码
const { http } = require('./require_modules');
const { port, host } = require('./config');
const { route } = require('./router');
function start() {
const server = http.createServer((req, res) => {
route(req, res);
});
server.listen(port, host, () => {
console.log(`server listening in http://${host}:${port}`);
});
}
module.exports = { start };
router.js
路由模块, 以及接口处理函数对照表
js
复制代码
const { url } = require('./require_modules');
const { host, port } = require('./config');
const { staticHanlder, indexHanlder, tableHanlder, notFind } = require('./hanlder');
const hanlder = {
'/index': indexHanlder,
'/static': staticHanlder,
'/index': indexHanlder,
'/getTableData': tableHanlder,
404: notFind
};
const route = (req, res) => {
const thisURL = new URL(`http://${host}:${port}${req.url}`);
let pathname = thisURL.pathname;
if (pathname === '/') {
pathname = '/index/';
}
const thisHanlder =
Object.entries(hanlder).find(([key, val]) => {
let reg = new RegExp(`^${key}/.*`);
return reg.test(pathname);
})?.[1] ?? hanlder[404];
thisHanlder(req, res, pathname);
};
module.exports = { route };
hanlder.js
接口处理函数模块
js
复制代码
const { fs, path, querystring } = require('../modules/require_modules');
const { getMimeType } = require('../modules/mime_type');
const { root } = require('./config');
const { host, port } = require('./config');
function staticHanlder(req, res, pathname) {
res.writeHeader(200, { 'content-type': getMimeType(pathname) });
const filePath = path.join(root, pathname);
fs.stat(filePath, (err, stats) => {
if (err) {
notFind(req, res, pathname);
return;
}
if (!stats) {
notFind(req, res, pathname);
return;
}
if (stats.isDirectory()) {
notFind(req, res, pathname);
return;
}
if (stats.isFile()) {
fs.readFile(filePath, (err, data) => {
if (err) {
notFind(req, res, pathname);
}
res.writeHeader(200, { 'content-type': getMimeType(pathname) });
res.end(data);
});
return;
}
});
}
function indexHanlder(req, res, pathname) {
res.writeHeader(200, { 'content-type': 'text/html;charset=utf-8' });
res.end(`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>index</title>
</head>
<body>
<h1>欢迎~</h1>
</body>
</html>`);
}
function tableHanlder(req, res, pathname) {
const thisURL = new URL(`http://${host}:${port}${req.url}`);
let search = thisURL.search.replace('?', '');
const searchInfo = querystring.parse(search);
let start = Number(searchInfo.start) || 0;
let end = Number(searchInfo.end) || start + 10;
const jsonPath = path.join(root, '/data/table.json');
fs.readFile(jsonPath, (err, data) => {
if (err) {
notFind(req, res, pathname);
return;
}
const jsonData = JSON.parse(data.toString('utf-8'));
const resData = jsonData.slice(start, end);
res.writeHeader(200, { 'content-type': 'application/json;charset=utf-8' });
res.end(JSON.stringify(resData));
});
}
function notFind(req, res, pathname) {
res.writeHeader(404, { 'content-type': 'text/html;charset=utf-8' });
res.end(`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>404</title>
</head>
<body>
<h1>not find</h1>
</body>
</html>`);
}
function serverError(req, res, pathname) {
res.writeHeader(500, { 'content-type': 'text/html;charset=utf-8' });
res.end(`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>500</title>
</head>
<body>
<h1>server error</h1>
</body>
</html>`);
}
module.exports = {
staticHanlder,
indexHanlder,
tableHanlder,
notFind,
serverError
};
mime_type.js
其它模块, 用于获取媒体文件类型
js
复制代码
const { path } = require('../modules/require_modules');
const MIME_TYPE = {
css: 'text/css',
gif: 'image/gif',
html: 'text/html',
ico: 'image/x-icon',
jpeg: 'image/jpeg',
jpg: 'image/jpeg',
js: 'text/javascript',
json: 'application/json',
pdf: 'application/pdf',
png: 'image/png',
svg: 'image/svg+xml',
swf: 'application/x-shockwave-flash',
tiff: 'image/tiff',
txt: 'text/plain',
wav: 'audio/x-wav',
wma: 'audio/x-ms-wma',
wmv: 'video/x-ms-wmv',
xml: 'text/xml'
};
function getMimeType(pathname) {
let ext = path.extname(pathname).replace('.', '').toLowerCase();
if (!ext) {
ext = pathname;
}
return MIME_TYPE[ext] || MIME_TYPE['txt'];
}
module.exports = {
getMimeType
};
config.js
其它模块 服务器基本信息配置
js
复制代码
module.exports = {
root: process.cwd(),
host: '127.0.0.1',
port: '3008'
};
- 其实这就是node框架express做的事情 封装服务器有着比较繁琐的过程, 这只是一个简单的模型演示, 比如需要封装上传文件的接口, 你可以用到第三方库multiparty, 需要处理ajax跨域, 你可以封装一个前面学的跨域处理函数 :-)