TL;DR 在一个应用中,完整的层级如下:
- 网络层 & 协议层(Network & HTTP Parsing)
- 抽象层(Request / Response / Context)
- 调度层(Router / Middleware)
- 业务层(Handler)
- 表现层(Response Rendering,如:HTML / JSON / File)
build from scratch
极简server
一个最简易app server需要什么呢?
- 设置好一个server socket,并监听某个端口,例如3000
- 接受client的连接
- 读取请求并处理
就是这么简单,我们已经可以通过访问server的ip和端口来访问server了。可是不对啊,我的HTTP去哪里了,我的网页又去哪里了?
别急,HTTP本身只是一个通信规则,规定了server和client之间如何通信。在使用curl或者浏览器时,会自动加上这个协议头,而在server端,需要自己解析这个协议头,并根据协议头来处理请求。而网页,就是处理的一种结果,把HTML写回给client由浏览器渲染出来的就是一个网页了。而我们常说的Request和Response,就是client socket和server socket之间的符合HTTP协议的通信内容。
那么现在我们多了一个步骤在server端,就是解析HTTP协议,并根据协议来处理请求。即:
- 设置好一个server socket,并监听某个端口,例如3000
- 接受client的连接
- 解析HTTP协议
- 根据解析出的协议来处理
Request并生成Response - 将
Response写回给client
Router & Middleware
说的简单,但是处理请求又具体指的是什么呢?
对于一个web应用来说,就是根据不同的url来处理不同的请求,可以是:
- 返回一个HTML页面
- 返回一个JSON数据
- 返回一个文件
- 重定向到另一个url
- …
那么,我们最好需要一个数据结构来存储这些url和对应的处理函数,也就是我们常说的Router。
同时,我们不难发现,平时上网的时候经常看到不同的url对应着不同的权限,方法,例如/api/..., /admin/...等,所以我们还需要一个RouterGroup来划分管理不同的路由。
对于这些Router,我们可能需要验证,logging或者其他操作,所以我们可以把这些操作抽象成Middleware。也就是说每个不同的RouterGroup甚至于每个Router 都可以有自己的Middlewares。
那么现在我们的server端需要做的事情就变成了:
- 设置好一个server socket,并监听某个端口,例如3000
- 接受client的连接
- 解析HTTP协议
- 根据解析出的协议和
Request来匹配对应的RouterGroup, - 找到对应的
Router和Handler - 基于需求使用
Middlewares和Handler来处理请求,并生成Response - 将
Response写回给client
Context
现在我们输入一串url,比如http://localhost:3000/api/v1/users,但进server端,我们就发现我们要带着一大堆东西传来传去,比如:
RequestResponse- 路由参数
- 状态
- 错误
- Middlewares
- …
所以,我们需要一个数据结构来存储这些东西,也就是我们常说的Context。