(Note: To better match the style and grammar of the target language, "Express-Go" is kept as is and placed before the action, and the sentence structure is slightly adjusted.)
如果你曾经使用过像 Express.js 这样的 Web 框架,你就会知道它们有多么便利和易用。现在,想象一下在 Go 语言中也能拥有这种便利性,同时还能享受其高性能和坚固性。正是这种想法促使我创造了 express-go,一个由 Express.js 启发的微型框架,并且最棒的是:我只用了 19 个小时就完成了!这段经历非常紧张,但每一秒都值得。让我来告诉你这一切是怎么发生的。官方仓库链接
错误更正:
已经下载的用户请注意,我忘记在go mod中添加仓库了。当时完成单元测试和示例后,太累就上传了,没注意到这点。现在我已经修正了这个问题,你可以正常安装了。
如何安装
在你的命令行中输入以下命令即可:
go get github.com/BrunoCiccarino/GopherLight/router go get github.com/BrunoCiccarino/GopherLight/req
想法
这一切始于我这么想:"拥有一些像 Express.js 一样简单的东东,但性能像 Go 一样好就更好了!" Go 很出名因为它既简洁又快,但当我写 web 服务器的时候,我感觉还是缺少一个像 Express.js 这样好用的东西。
于是我不再抱怨,而是决定亲自动手做一些事情。我决定创建一个微框架,让我能够快速轻松地设置路由、快速轻松地处理HTTP请求和响应。
旅程开始了
我从最基本的部分开始:一个能够监听HTTP请求的Go应用程序,并根据不同的路由路径执行不同的任务。
首先:路线介绍
首先,我需要配置路由。我希望能够像在Express.js里那样定义路由,比如,指定一个URL和相应的处理函数。
这就是路由的魔力:
type App struct { // 应用结构
routes map[string]func(req *req.Request, res *req.Response)
}
func NewApp() *App { // 创建一个新的App实例
return &App{
routes: make(map[string]func(req *req.Request, res *req.Response)),
}
}
func (a *App) Route(path string, handler func(req *req.Request, res *req.Response)) { // 设置路由
a.routes[path] = handler
}
func (a *App) ServeHTTP(w http.ResponseWriter, r *http.Request) { // 实现HTTP服务器的处理逻辑
if handler, exists := a.routes[r.URL.Path]; exists {
request := req.NewRequest(r)
response := req.NewResponse(w)
handler(request, response)
} else {
http.NotFound(w, r)
}
}
func (a *App) Listen(addr string) error { // 开始监听指定地址上的HTTP请求
return http.ListenAndServe(addr, a)
}
全屏显示 退出全屏
这个想法很简单:我想有一个路由映射,键是URL,值是处理请求的函数,它是一个字符串到函数的映射。
处理器的魔法
我喜欢Express.js的一个地方是它的路由处理程序非常易用。因此,每个路由都被视为一个函数,接收请求和响应两个参数。相比之下,在Go中,这需要更多手动操作,因为标准库缺乏方便的功能,所以我写了一些抽象来简化这个过程。
关于如何处理请求
在 Go 中处理 HTTP 请求涉及很多结构和方法,我将这些封装到一个名为 Request 的结构体中,并提供了一些方便的方法来获取查询参数、头部信息以及请求体。
// 定义一个请求结构体
type Request struct {
Req *http.Request
Body string
}
// 创建一个新的Request实例
func NewRequest(req *http.Request) *Request {
// 读取请求体并转换为字符串
bodyBytes, _ := io.ReadAll(req.Body)
bodyString := string(bodyBytes)
// 返回新的Request实例
return &Request{
Req: req,
Body: bodyString,
}
}
// 查询请求参数
func (r *Request) QueryParam(key string) string {
params := r.Req.URL.Query()
return params.Get(key)
}
// 获取请求头部信息
func (r *Request) Header(key string) string {
return r.Req.Header.Get(key)
}
// 获取请求体
func (r *Request) BodyAsString() string {
return r.Body
}
全屏查看 退出全屏
现在,我无需再直接处理http.Request,而是可以这样做:
app.Route("/greet", func(r *req.Request, w *req.Response) {
name := r.QueryParam("name")
if name == "" {
name = "Guest"
}
w.Send("你好," + name + ",很高兴见到你!")
})
// 处理/greet请求,根据查询参数name生成问候语.
切换到全屏,退出全屏
这样一来,事情就变得更好读、更干净了!
轻松应对
请求发送完毕之后,是时候简化发送响应的过程了。响应也需要简洁,这样我就能快速发送文本或JSON。
定义一个 `Response` 结构体,它包含一个 `HTTP 响应写入器`。
创建一个新的 `Response` 实例。
(`res` 是一个 `Response` 实例) 发送数据。
(`res` 是一个 `Response` 实例) 设置状态码。
(`res` 是一个 `Response` 实例) 将数据编码为 JSON 并发送。
全屏 退出全屏
结果是
在这些19小时的工作后,我成功地开发出了express-go:它是一个快速又易于使用的微框架,配置路由和发送响应与使用Express.js一样简单,但具备Go的强大功能和性能。
用法示例:
这里有一个完整的例子来展示这一切是如何拼凑起来的。
package main
import (
"github.com/BrunoCiccarino/GopherLight/router"
"github.com/BrunoCiccarino/GopherLight/req"
"fmt"
)
func main() {
app := router.NewApp()
app.Route("/hello", func(r *req.Request, w *req.Response) {
w.Send("Hello, World!")
})
app.Route("/json", func(r *req.Request, w *req.Response) {
w.JSON(map[string]string{"message": "Hello, JSON"})
})
fmt.Println("Server listening on port 3333")
app.Listen(":3333")
}
切换到全屏 退出全屏
简单,干净,直截了当。我很自豪,能在一天之内搞定它,而且它有足够的灵活性来应对小项目,而没有大型框架的复杂度。
最后的思考
在19小时之内创建express-go是一段既有趣又具挑战性的经历。我专注于解决在Go服务器上遇到的实际难题,并尽量使一切直观。当然,还有很多好玩的功能和工具可以试一试,但还有更多的工作要做!
如果你对这个感兴趣,可以看看代码,也欢迎贡献。毕竟,这样做,像这样的工具建设过程分享出来会更酷!
现在,如果你们允许,我要去拿杯咖啡,……连续工作了19小时之后,我应该享受一下,对不对?
共同学习,写下你的评论
评论加载中...
作者其他优质文章