请求和错误处理
在ZKWeb中处理Http请求会使用Http请求处理器(IHttpRequestHandler),
上一篇介绍的控制器只是其中的一个处理器.
自己实现处理器可以处理更复杂的url, 例如返回静态文件等.
Http请求的整体流程图

流程的伪代码请看最下面.
Http请求处理器
这是IHttpRequestHandler的一个简单的例子,
访问/example/handler/xxx的时候会返回the path is xxx.
[ExportMany] public class HttpRequestHandlerExample : IHttpRequestHandler { public const string Prefix = "/example/handler/"; public void OnRequest() { var request = HttpManager.CurrentContext.Request; var response = HttpManager.CurrentContext.Response; if (request.Path.StartsWith(Prefix)) { new PlainResult("the path is " + request.Path.Substring(Prefix.Length)) .WriteResponse(response); response.End(); } } }
需要注意的是, 请求处理器会按注册顺序的相反顺序调用,
越后面注册的处理器调用的越前,
如果前面的处理器调用了response.End(), 就不会再调用后面的处理器了.
Http请求预处理器
有的情况下, 您可能想给所有Http请求添加一个自定义的Header,
但是如果使用IHttpRequestHandler, 又很难保证注册的处理器是最后注册的.
ZKWeb针对这种情况提供了另外一个接口IHttpRequestPreHandler.
[ExportMany] public class AddVersionHeaderHandler : IHttpRequestPreHandler { public void OnRequest() { var response = HttpManager.CurrentContext.Response; response.AddHeader("X-ZKWeb-Version", Application.FullVersion); } }
IHttpRequestPreHandler可以保证在所有IHttpRequestHandler前调用,
注意IHttpRequestPreHandler中不应该写入Response和调用response.End().
Http请求的后处理器
同样的, 如果您想在所有Http请求处理后执行一些自定义的操作,
可以使用IHttpRequestPostHandler接口, 这个接口的使用跟上面一样,
只是它会保证在所有IHttpRequestHandler之后执行.
Http请求包装器
有时候您可能会想同时使用预处理器和后处理器, 也就是想把请求嵌套在using里面,
同时使用上面的IHttpRequestPreHandler和IHttpRequestPostHandler可能比较困难.
这时候可以使用IHttpRequestHandlerWrapper.
这个接口的使用跟Owin, Asp.Net Core的中间件比较相似.
[ExportMany] public class ExampleWrapper : IHttpRequestHandlerWrapper { public Action WrapHandlerAction(Action action) { return () => { using (SomeScope()) { action(); } }; } }
如果您只考虑控制器, 也可以使用前一篇提到的Action过滤器.
Http错误处理器
ZKWeb提供了一个专门的错误处理器,
注册IHttpRequestErrorHandler接口即可全局处理请求中的错误.
[ExportMany] public class HttpErrorHandlerExample : IHttpRequestErrorHandler { public void OnError(Exception ex) { var httpEx = ex as HttpException; // HttpException in ZKWebStandard.Web if (httpEx != null && httpEx.StatusCode == 404) { var response = HttpManager.CurrentContext.Response; new PlainResult("custom 404 page").WriteResponse(response); response.End(); } } }
如果有多个错误处理器, 会按注册顺序的相反顺序调用,
如果其中一个调用了response.End()则不继续调用.
Http请求的整体流程
上面的处理器的整体调用流程是:
try {
try {
按注册顺序枚举IHttpRequestPreHandler {
调用OnRequest函数
}
处理函数 = new Action ({
按注册顺序的相反顺序枚举IHttpRequestHandler {
调用OnRequest函数 <= 控制器会在这里调用
}
抛出404错误
})
按注册顺序枚举IHttpRequestHandlerWrapper {
处理函数 = wrapper.WrapHandlerAction(处理函数)
}
调用处理函数
} finally {
按注册顺序枚举IHttpRequestPostHandler {
调用OnRequest函数
}
}
} catch (代表请求结束的例外) {
处理请求完成
} catch (Exception ex) {
try {
按注册顺序的相反顺序枚举IHttpRequestErrorHandler {
调用OnError函数
}
} catch (代表请求结束的例外) {
处理错误完成
}
}
ZKWeb默认注册的IHttpRequestHandler就是ControllerManager,
而默认注册的IHttpRequestErrorHandler则会记录错误日志到App_Data\logs下.