deno-http-middleware
Deno
原生 HTTP 服务器的中间件框架
也提供了对于nodejs
环境的适配
这个中间件框架受到Koa
的启发
核心模块保持简洁,完全函数式编程,
允许在中间件中直接返回响应或者替换修改请求对象.
尽可能使用新的原生 API
,不需要引入更多的复杂性.
对于请求的解析,使用URLSearchParams
,URL
,Request.prototype.json
,Request.prototype.text
,代替bodyParser
,querystring
,parseurl
.
对于路由匹配,可以使用新的原生URLPattern
,不使用类似于koa-Router
之类的方案.
对于响应体的构建也可以使用原生Response
实现大部分的响应体的编码.
返回的Response
的部分属性中的body
可以是任何类型,可以添加自定义中间件来把指定类型的body
转换成原生Response
接受的body
类型.
其余常用功能在deno
的标准库中有解决方案.比如说cookie
,和静态文件服务.
介绍
getOriginalRequest
函数
可以获得原本的请求对象
createHandler
函数
根据中间件创建一个请求处理函数
接收参数middleware
:中间件Middleware
的数组
接受可选参数 notfoundHandler
:自定义全局未找到错误处理函数。
接受可选参数 errorHandler
:自定义错误处理函数
接受可选参数 responseBuilder
:自定义响应构建函数
接受可选参数 retProcessor
:自定义中间件返回值处理函数
Middleware
中间件函数可以是异步函数
接受参数上下文context
对象和调用下一个中间件的函数next
可以返回Response
或者Request
或者{response:Response,request:Request}
或者Response
的部分属性,来修改上下文Context
中的请求和响应对象,
返回值中也可以设置参数next
表示中间件是否需要执行next
函数.
也可以不返回,不做任何修改
返回的Response
的部分属性中的body
可以是任何类型,可以添加自定义中间件来把指定类型的body
转换成原生Response
接受的body
类型.
context
对象
上下文包含属性request
:Request
对象的部分属性,属性可修改
因为原本的Response
,Request
的属性都是不可修改的,所以不用原本的Response
,Request
对象
包含属性response
:Response
对象的部分属性,属性可修改
自带中间件
conditional_get
:条件GET
请求中间件
cors
:完全跨域GET
请求中间件
logger
:日志中间件
json_builder
:JSON
响应中间件,并附带etag
响应头
etag_builder
:给响应体不是 stream
的提供etag
响应头的中间件
method_override
:覆盖请求方法的中间件,getOriginalMethod
函数可以获得原本的请求方法.
stream_etag
:把响应体从 stream
转换为 buffer
来计算 etag
的中间件
安装教程
Deno
1.21.1
使用说明
使用 npm 安装
npm i "@masx200/deno-http-middleware"
也可以从 deno.land
导入
https://deno.land/x/masx200_deno_http_middleware/mod.ts
https://deno.land/x/masx200_deno_http_middleware/middleware.ts
使用自带的中间件举例
import {
conditional_get,
cors,
etag_builder,
getOriginalMethod,
json_builder,
logger,
method_override,
stream_etag,
} from "https://deno.land/x/masx200_deno_http_middleware/middleware.ts";
const handler = createHandler([
logger,
conditional_get,
method_override(),
cors(),
json_builder,
etag_builder,
stream_etag(),
(ctx) => {
const body = {
original_Method: getOriginalMethod(ctx),
override_method: ctx.request.method,
};
return { body };
},
]);
nhttp
的hello world
类似简单的例子,注意顺序,中间件返回response
的部分属性
import { serve } from "https://deno.land/std@0.138.0/http/server.ts";
import { createHandler } from "https://deno.land/x/masx200_deno_http_middleware@1.2.1/mod.ts";
const port = Math.floor(Math.random() * 10000 + 10000);
const handler = createHandler([
async (ctx, next) => {
console.log(1);
await next();
console.log(3);
},
(ctx) => {
console.log(2);
return { body: "hello world," + ctx.request.url };
},
]);
const p = serve(handler, { port: port });
await p;
koa
的hello world
类似简单的例子,注意顺序,中间件直接修改response.body
import { serve } from "https://deno.land/std@0.138.0/http/server.ts";
import { createHandler } from "https://deno.land/x/masx200_deno_http_middleware@1.2.1/mod.ts";
const port = Math.floor(Math.random() * 10000 + 10000);
const handler = createHandler([
async (ctx, next) => {
console.log(1);
await next();
console.log(3);
},
(ctx) => {
console.log(2);
ctx.response.body = "hello world," + ctx.request.url;
return;
},
]);
const p = serve(handler, { port: port });
await p;
json builder 举例
自带的 json 响应构建中间件的部分代码的例子
import { isPlainObject } from "../deps.ts";
import { JSONResponse } from "../response/JSONResponse.ts";
import { Middleware, RetHandler } from "../src/Middleware.ts";
export const json_builder: Middleware = async function (
context,
next,
): Promise<RetHandler> {
await next();
const { response } = context;
const { body } = response;
return response instanceof Response
? response
: Array.isArray(body) || isPlainObject(body)
? await JSONResponse(response)
: void 0;
};
自定义错误处理程序
const h1: Middleware = async (_ctx, next) => {
try {
await next();
} catch (error) {
return new Response(error?.message, { status: 500 });
}
};
const h2: Middleware = () => {
throw new Error("1");
};
const composed = handler(h1, h2);
nodejs
上运行一个简单的 http
服务器
在 import {
getIncomingMessage,
json,
listener,
} from "@masx200/deno-http-middleware";
import { createServer } from "http";
const server = createServer(
listener(
async (_ctx, next) => {
try {
await next();
} catch (error) {
return new Response(error?.message, { status: 500 });
}
},
(ctx, next) => {
const socket = getIncomingMessage(ctx).socket;
const { localAddress, localPort, remoteAddress, remotePort } =
socket;
return json({
localAddress,
localPort,
remoteAddress,
remotePort,
method: ctx.request.method,
url: ctx.request.url,
headers: Object.fromEntries(ctx.request.headers),
});
},
),
);
const port = 9000;
server.listen(port, () => console.log("http server listening port:" + port));
//server.close();