前言
时至2021年,nodejs在web开发领域有着举足轻重的地位,常被应用于各种业务中间件开发以及构建工具插件开发,其web框架如express、koa、fastify、egg、midway、nest等也有一定的应用空间。本文将结合常见mvc框架特性,重点阐述nodejs在web mvc框架领域中的应用价值。希望对有兴趣自己封装框架的童鞋有所帮助!
正文
常见mvc框架核心功能如下:1.请求/响应的统一处理机制;2.静态资源映射;3.http请求分发。本文将对以上3个问题点进行阐述,分别讲述解决方案!
1 请求/响应的统一处理机制
这个问题利用http模块拦截机制实现,拦截原型如下:
function createServer(requestListener?: RequestListener): Server;
function createServer(options: ServerOptions, requestListener?: RequestListener): Server;
type RequestListener = (req: IncomingMessage, res: ServerResponse) => void;
createServer函数接受一个请求监听器,该监听器包含了请求和响应对象,可以定义拦截器对请求响应的统一处理,如下进行了简单跨域处理:
export default function interceptor(req, res) {
console.log(`request ${req.url} is targeted!`.green.bold);
// 跨域处理
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Headers", "*");
res.setHeader("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
}
2 静态资源映射
在对静态资源映射前,首先需要区分接口请求和资源请求,如接口请求则转发给业务代码进行处理,资源请求则直接读取本地文件返回即可。因此,需要解决以下问题:
(1)区分接口请求和资源请求
简单区分可以采用url前缀进行区分,以/api开头的为接口请求,否则为资源请求。
export default async function(req, res) {
try {
if (req.url.startsWith('/api')) { //接口请求
await dispatchActions(req, res)
} else { //资源请求
...
}
} catch (error) {
console.error(error);
res.statusCode = 500;
res.end('服务器异常');
}
}
资源请求又可细分为后端资源请求和前端资源请求,因此需要添加响应配置项进行处理。
let path;
const urlObj = new URL(req.url, globalThis.$HOST);
if (req.url.startsWith('upload')) { // 后端资源请求
path = join(cwd(), urlObj.pathname);
} else { // 前端资源请求
let pathname = urlObj.pathname === '/' ? '/index.html' : urlObj.pathname;
path = join(cwd(), config.views, pathname);
}
(2)对资源请求设置适当的ContentType
Content-Type对照表可以获取常用文件后缀以及对应的contentType,通过工具类处理响应即可。
async function setContentType(path, res) {
try {
let contentType;
if (path.includes('.')) {
const suffix = '.' + path.split('.')[1];
metaData[suffix] ? (contentType = metaData[suffix]) : (contentType = metaData['.*']);
}
if (contentType === 'text/html' || contentType === 'text/plain') {
contentType += ';charset=utf-8';
}
if (contentType) {
res.setHeader('Content-Type', contentType);
}
} catch (error) {
console.error(error)
}
}
3 http请求分发
(1) 编写请求分发函数
async function dispatchActions(req, res) {
const urlObj = new URL(req.url, globalThis.$HOST);
const api = urlObj.pathname.split('/api')[1];
if (getControllerExport()[api]) {
await getControllerExport()[api](req, res);
} else {
res.statusCode = 404;
res.end('not found');
}
}
export function setControllerExport(data) {
globalThis.$CONTROLLER = data;
}
export function getControllerExport() {
return globalThis.$CONTROLLER;
}
(2) 仿照webpack require.context功能实现读取同一文件下的其他文件的默认导出
// controll/index.mjs
async function autoImpotController(dir, exclude) {
let result = {};
const files = await readdir(dir);
if (files?.length) {
for (let i = 0; i < files.length; i++) {
if (exclude !== files[i]) {
const module = await import('./' + files[i]);
result = {...result, ...module.default};
}
}
}
setControllerExport(result);
}
const fileUrl = import.meta.url;
const dir = dirname(fileURLToPath(fileUrl));
const exclude = basename(fileURLToPath(fileUrl));
autoImpotController(dir, exclude);
(3) 编写controller
// controll/user.mjs
const base="/user";
const controllers = {
getUsername : async function (req, res) {
try {
res.setHeader('Content-Type', 'application/json;charset=utf-8');
res.end(getJsonResult(true, 'getUsername'));
} catch (error) {
throw new Error(error);
}
}
}
const ept = {};
Object.keys(controllers).forEach(controller => {
ept[`${base}/${controller}`] = controllers[controller];
})
export default ept;
4 基于注解的controller开发
经过查询资料发现,基于typescript的注解开发处于实验阶段,而ecmascript注解提案处于第二阶段,详见github.com/tc39/propos… ,本文暂时不作探究,感兴趣的童鞋可以自行研究下!最终的controller写法应类似:
@controller({baes: 'uesr'})
class UserController {
@Request({path: '/user', method: 'GET', contentType: 'application/json;charset=utf-8'})
async getUsername() {
try {
res.setHeader('Content-Type', 'application/json;charset=utf-8');
res.end(getJsonResult(true, 'getUsername'));
} catch (error) {
throw new Error(error);
}
}
}
5 欢迎访问原文链接
欢迎访问我的博客-利用nodejs仿express对http模块进行简易封装
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!