具体代码看Github
完整框架看Github
上下文
设计Context
- 对于Web服务来说,无非是根据
*http.Request,响应http.ResponseWriter。但是这两个接口提供的方法粒度太细。 当我们想要返回一个完成的响应,需要考虑响应头和响应体,其中响应头中又包含响应状态码,响应消息类型等等。而且每次都需要 这样操作,显得太繁琐 - 使用Context将请求对象和响应对象进行封装,优化用户的使用体验,并且对一些操作进行自定义
思考一下,请求上下文需要在哪里创建?
- 之前我们聊过,
ServeHTTP方法向前对接用户[浏览器],向后对接Web框架 - 请求上下文肯定是用户请求对来了的时候创建,对吧,因此得出结论:在
ServeHTTP中创建
问题又来了,构建了请求上下文应该怎么用,或者说,应该给谁用?
- 给视图函数用啊,视图函数拿到上下文,解析请求对象,响应数据
- 我们之前的
HandlerFunc视图函数签名这时候需要改了,接收的参数不再是*http.Request和http.ResponseWriter,而直接是上下文对象type HandlerFunc func(ctx Context)
好了,视图函数拿到了请求上下文,那怎么用呢?你不可能既让我用上下文,对一些常用的操作还得我手写吧? 换个问法就是,上下文需要提供怎样的API?
- 统一的响应
- 状态码设置
- 响应体的设置
- 响应数据格式的设置
- 提供多种响应方式
- JSON格式
- 纯文本格式
- HTML格式
- ...
上述的都是对于响应的封装,那对请求的封装呢?
- 获取查询参数【Query类型】
- 获取请求参数【Param类型】
http://www.baidu.com/user/1?username=jason&password=jason123 1. 其中,"1"表示请求参数 2. "username=jason"和"password=jason123"表示查询参数 - 获取到请求体数据
思考
目前我们的框架设计得合理吗?
目前从市面上主流的Web框架上来看,一个框架需要的如下几个"组件"(暂时叫做组件)
- 引擎:盘活整个框架的核心
- 路由树:包括路由和视图函数的绑定
- 上下文
- AOP方案:面向切面编程。类中间件
- ...
根据目前我们实现的部分:引擎和路由树还是耦合在一起的
引擎只是组合整个框架,不做其他任何的特别操作。包括添加路由、匹配路由等等
它就有点像net/http包中的Handler接口一样,只作为一个中间桥梁,转发请求和响应结果
- router为engine提供注册路由API,它是核心API
- engine提供用户提供注册路由API,它是衍生API
- router提供查找路由功能,并执行命中的视图函数。就将
ServeHTTP中的一部分逻辑抽离出来