个人技术日常分享

手写一个微型Spring框架(三):NHttpContext的详解

2025/04/30

在Javelin框架中,NHttpContext类在HTTP请求处理流水线中扮演着至关重要的角色。它是一个封装了请求-响应生命周期各个方面的对象,管理着HTTP请求的各个环节。下面我们将深入探讨NHttpContext的功能、组成部分及其设计思路。


NHttpContext概述

NHttpContext是一个容器,保存了处理HTTP请求所需的所有必要元素。它不仅代表当前HTTP交换的状态,还管理流水线上下文、日志记录、错误处理等内容。其设计使其成为HTTP请求生命周期中的主要上下文对象,提供了一种有组织的方式来管理请求和响应。

NHttpContext

以下是NHttpContext中主要属性的介绍:

  1. HttpExchange exchange
    这是实际的HTTP交换对象,代表了HTTP请求和响应。它是Java HTTP服务器提供的标准HttpExchange对象,但在Javelin中,它被封装在NHttpContext中,以便提供更简洁和定制化的处理流程。

  2. HttpPipelineContext pipelineContext
    pipelineContext负责管理HTTP请求处理流水线的各个阶段。这个流水线包括路由、认证、日志记录等步骤。它确保HTTP请求在每个阶段都能被正确处理。

  3. OprLogScope oprLogScope
    该对象用于在请求处理过程中管理日志记录的作用域。它允许Javelin在特定的作用域内创建和处理日志,确保与特定HTTP请求相关的日志能被准确捕捉。

  4. Exception lastException
    如果在请求处理过程中发生任何异常,这个字段存储最后的异常。这个功能对调试非常有用,因为它允许开发者访问可能干扰HTTP请求处理的异常信息。

  5. boolean skipAuthentication
    该布尔标志控制是否跳过当前请求的认证。对于某些请求,不需要认证时可以设置为true,这样请求就不需要经过认证步骤。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class NHttpContext {
public HttpExchange exchange;
public HttpPipelineContext pipelineContext;
public OprLogScope oprLogScope;
public Exception lastException;
public boolean skipAuthentication;

public NHttpContext(HttpExchange exchange, RouteDefinition routeDefinition) {
this.exchange = exchange;
this.pipelineContext = HttpPipelineContext.start(this);
this.pipelineContext.routeDefinition = routeDefinition;
}

void setOprLogScope(OprLogScope oprLogScope) {
this.oprLogScope = oprLogScope;
}

public void httpReply(int statusCode, String message) {
try {
this.exchange.sendResponseHeaders(statusCode, 0);
this.exchange.getResponseBody().write(message.getBytes());
this.exchange.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}


HttpPipelineContext 类

HttpPipelineContext 类主要负责管理与请求处理流水线相关的信息。其功能包括:

  • processId:每个请求都应该有一个唯一的 ID,方便跟踪和调试。
  • startTimeendTime:记录请求的开始和结束时间,用于性能分析和日志记录。
  • routeDefinition:该字段关联当前请求处理的路由定义,确保请求按正确的路由规则进行处理。
  • setException:设置请求处理过程中发生的异常,便于在整个流程中传递和记录错误。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public class HttpPipelineContext {
public String processId;
public Date startTime;
public Date endTime;
public NHttpContext httpContext;
public RouteDefinition routeDefinition;
public Exception lastException;

public static HttpPipelineContext start(NHttpContext httpContext) {
HttpPipelineContext pipelineContext = new HttpPipelineContext(httpContext);

OprLogScope oprLogScope = OprLogScope.start(httpContext.pipelineContext);
pipelineContext.httpContext.setOprLogScope(oprLogScope);

return pipelineContext;
}

public void setRouteDefinition(RouteDefinition routeDefinition) {
this.routeDefinition = routeDefinition;
}

private HttpPipelineContext(NHttpContext httpContext) {
if (httpContext == null) {
throw new IllegalArgumentException("httpContext cannot be null");
}
this.httpContext = httpContext;
httpContext.pipelineContext = this;
}

public void setException(Exception ex) {
if (ex != null) {
httpContext.lastException = ex;
}
}

public void completeRequest() {
throw new AbortRequestException();
}

public void dispose() {
this.httpContext = null;
}
}

OprLogScope 类

OprLogScope 类负责在请求的生命周期内进行操作日志的记录和异常的处理。它的设计包括:

  • steps:记录操作的每个步骤。
  • oprlog:操作日志对象,记录请求处理过程中的各项操作。
  • start:启动操作日志范围的方法,负责创建和初始化操作日志。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class OprLogScope {
private List<StepItem> steps;
public OprLog oprlog;

public static OprLogScope start(HttpPipelineContext pipelineContext) {
OprLogScope scope = new OprLogScope();
scope.oprlog = OprLog.create(pipelineContext);
return scope;
}

public int setException(Exception ex) {
return oprlog.setException(ex);
}

public int saveOprLog(HttpPipelineContext pipelineContext) {
LogHelper.Write(this.oprlog);
return 1;
}
}

NHttpContext的设计思路

在设计NHttpContext时,重点考虑了模块化、扩展性、易用性以及与Javelin框架中的其他组件的集成。作为Javelin HTTP请求处理流水线的一部分,NHttpContext的设计思路围绕着以下几个核心原则展开:

单一责任原则(Single Responsibility Principle)

NHttpContext的设计遵循单一责任原则,它主要负责管理和维护一个HTTP请求生命周期中的各种上下文信息。通过将HTTP交换的相关信息(如请求、响应、路由信息、日志记录等)集中到一个对象中,NHttpContext避免了将过多责任分散到多个地方,从而提升了代码的可读性和可维护性。

责任划分:

  • HttpExchange:处理请求和响应。
  • HttpPipelineContext:管理HTTP请求处理的流水线上下文,确保请求按顺序经过不同阶段的处理。
  • OprLogScope:处理日志记录的作用域,确保所有操作的日志能够被正确追踪。
  • Exception:捕捉并存储在请求处理过程中出现的异常信息。

灵活的流水线处理(Flexible Pipeline Handling)

NHttpContext将HTTP请求处理流程分为多个阶段,每个阶段由HttpPipelineContext负责。这使得Javelin的请求处理流水线具有很高的灵活性和可定制性,开发者可以根据具体需求在不同阶段插入中间件、路由逻辑、认证步骤等。

  • 流水线的动态性HttpPipelineContext会根据具体的路由定义和配置动态调整请求的处理流程。每次请求的流水线都可以根据具体的业务需求进行配置,使得请求处理过程更加高效和灵活。

高度模块化(Modularization)

NHttpContext的设计中,各个功能模块之间的耦合度较低。例如,HttpExchangeHttpPipelineContext之间并没有强依赖,而是通过NHttpContext进行解耦,使得每个模块都能够独立工作并实现其特定功能。

  • 分离关注点:日志处理、异常处理、HTTP请求和响应的处理等不同的关注点被封装在不同的对象中,使得每个对象都专注于其核心功能。
  • 扩展性:这种设计使得开发者可以根据需求向NHttpContext中添加新的处理模块,例如,新的认证方式、日志记录策略等,保持了较高的扩展性。

集成式错误处理(Integrated Error Handling)

NHttpContext内建了异常处理机制,通过lastException字段记录发生的异常,使得开发者能够快速定位和处理错误。错误信息被集中管理,有助于后续的调试和问题追踪。

  • 集中管理异常NHttpContext会捕获并存储处理过程中发生的异常,避免了异常分散在各个模块中。这样开发者可以通过lastException迅速获取异常详情,并进行统一的处理。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class ActionExecutor {
public void execute(NHttpContext context) throws Exception {
try{
// ...
handlerRequest(context);
} catch ( AbortRequestException e) {
// 提前结束请求,啥也不干了
} catch (Exception e) {
Throwable cause = e.getCause();
// 记录原始异常
context.pipelineContext.setException((Exception)cause);
app.onError(context);
} finally {
app.endRequest(context);
}

}

响应处理简化(Simplified Response Handling)

NHttpContext提供了一个简单的接口httpReply,用于发送响应。通过该接口,开发者无需过多关注底层的HttpExchange细节,而只需传递状态码和响应体。这样简化了响应处理流程,提高了开发效率。

  • 简洁的APIhttpReply方法为响应发送提供了统一的接口,使得请求的响应处理变得直观和高效。
  • 自动化的关闭连接:在异常发生后,调用httpReply方法自动关闭HttpExchange连接,无需手动干预。

面向操作的日志记录(Operation-Oriented Logging)

NHttpContext设计了OprLogScope来管理每个HTTP请求的操作日志。这使得每个请求的日志记录都能与当前操作(例如,路由、认证等)相关联,方便进行精准的日志追踪。

  • 作用域管理OprLogScope允许每个请求在特定的操作上下文内生成日志。这种方式增强了日志的可读性,帮助开发者清晰地追踪每个请求在不同阶段的执行情况。
  • 日志隔离:通过为每个请求提供独立的日志作用域,避免了不同请求之间日志的混淆,提高了日志的准确性和可操作性。
1
2
3
4
5
6
7
8
public static HttpPipelineContext start(NHttpContext httpContext) {
HttpPipelineContext pipelineContext = new HttpPipelineContext(httpContext);
// 为每个请求创建独立的日志作用域
OprLogScope oprLogScope = OprLogScope.start(httpContext.pipelineContext);
pipelineContext.httpContext.setOprLogScope(oprLogScope);

return pipelineContext;
}

可配置的认证机制(Configurable Authentication Mechanism)

NHttpContext通过skipAuthentication标志允许开发者灵活地控制是否需要认证。这使得在某些场景下(如公共API或不需要身份验证的请求)可以跳过认证过程,减少了不必要的性能开销。

  • 认证跳过机制:开发者可以根据业务需求灵活地跳过认证步骤,而无需修改底层认证逻辑。
  • 灵活性:认证机制的可配置性增加了框架的灵活性,使得它能够适应不同类型的Web应用。

在认证中间件里面我们可以这样使用:
1
2
3
4
5
6
7
8
9
public void authenticateRequest(NHttpContext httpContext) throws Exception {
// 如果skipAuthentication为true,则跳过认证
if (httpContext.skipAuthentication)
return;

for (NHttpModule module : modules) {
module.authenticateRequest(httpContext);
}
}

结论

NHttpContext类是Javelin框架中处理HTTP请求的关键组件之一。它帮助封装了请求-响应管理的核心元素,提供了一个有组织的方式来处理HTTP交换,包括认证、日志记录、异常处理和响应生成。

通过理解并使用NHttpContext,开发者可以更好地管理和定制HTTP请求的处理行为,确保应用保持模块化、可维护且高效。当然目前这个类还有很多缺点,后续我会在过程中继续完善。中间很多的细节没有展开,大家可以自行查看源码。

由于篇幅原因,示例中的代码仅展示了部分关键实现细节,完整代码请参考GitHub仓库。

CATALOG
  1. 1. NHttpContext概述
  2. 2. HttpPipelineContext 类
  3. 3. OprLogScope 类
  4. 4. NHttpContext的设计思路
    1. 4.1. 单一责任原则(Single Responsibility Principle)
    2. 4.2. 灵活的流水线处理(Flexible Pipeline Handling)
    3. 4.3. 高度模块化(Modularization)
    4. 4.4. 集成式错误处理(Integrated Error Handling)
    5. 4.5. 响应处理简化(Simplified Response Handling)
    6. 4.6. 面向操作的日志记录(Operation-Oriented Logging)
    7. 4.7. 可配置的认证机制(Configurable Authentication Mechanism)
    8. 4.8. 在认证中间件里面我们可以这样使用:123456789public void authenticateRequest(NHttpContext httpContext) throws Exception { // 如果skipAuthentication为true,则跳过认证 if (httpContext.skipAuthentication) return; for (NHttpModule module : modules) { module.authenticateRequest(httpContext); }}
  5. 5. 结论