【Go】手写简易go webserver

核心:实现net/http库中handler接口的ServeHTTP方法的实例,通过http.ListenAndServe注册后,所有的请求都会打到该实例的ServeHTTP方法里。Context是对请求对象和响应对象的封装,实现了获取请问请求参数、设置状态码、设置响应头、设置响应类型、设置响应体等方法。

1 项目结构

在这里插入图片描述

2 constant.go

package constantconst (DefaultMaxMemory = 32 << 20 // 32 MBSeparator = "_"
)

3 context.go

package contextimport ("encoding/json""mini_gee/constant""net/http"
)type HandleFunc func(context *Context)type Context struct {w        http.ResponseWriterr        *http.RequestPath     stringMethod   stringHandlers []HandleFuncindex    int
}func NewContext(w http.ResponseWriter, r *http.Request) Context {return Context{w:      w,r:      r,Path:   r.URL.Path,Method: r.Method,index:  -1,}
}func (c *Context) Next() {c.index++for c.index < len(c.Handlers) {c.Handlers[c.index](c)c.index++}
}func (c *Context) SetHeader(key, value string) {c.w.Header().Set(key, value)
}func (c *Context) SetStatusCode(code int) {c.w.WriteHeader(code)
}func (c *Context) GetPostForm(key string) (string, bool) {if c.r.PostForm == nil {c.r.ParseMultipartForm(constant.DefaultMaxMemory)}has := c.r.PostForm.Has(key)if !has {return "", false}return c.r.PostForm.Get(key), true
}func (c *Context) PostForm(key string) string {return c.r.PostFormValue(key)
}func (c *Context) GetQuery(key string) (string, bool) {has := c.r.URL.Query().Has(key)if !has {return "", false}return c.r.URL.Query().Get(key), true
}func (c *Context) Query(key string) string {return c.r.URL.Query().Get(key)
}func (c *Context) String(code int, text string) {c.SetHeader("Content-Type", "text/plain")c.SetStatusCode(code)_, err := c.w.Write([]byte(text))if err != nil {http.Error(c.w, err.Error(), http.StatusInternalServerError)}
}func (c *Context) JSON(code int, data interface{}) {c.SetHeader("Content-Type", "application/json")c.SetStatusCode(code)jsonData, err := json.Marshal(data)if err != nil {http.Error(c.w, err.Error(), http.StatusInternalServerError)}_, err = c.w.Write(jsonData)if err != nil {http.Error(c.w, err.Error(), http.StatusInternalServerError)}
}

4 engine.go

package engineimport ("fmt""mini_gee/constant""mini_gee/context""net/http"
)type Engine struct {middlewares []context.HandleFunchandlers    map[string]context.HandleFunc
}func New() *Engine {return &Engine{handlers: make(map[string]context.HandleFunc),}
}func (e *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {ctx := context.NewContext(w, r)defer func() {if err := recover(); err != nil {message := fmt.Sprintf("catch error: %v", err)fmt.Println(message)ctx.String(200, message)}}()method := r.Methodpath := r.URL.Pathkey := makeHandlerKey(method, path)handler, ok := e.handlers[key]if !ok {ctx.String(http.StatusNotFound, "handler not found")return}var handlers []context.HandleFunchandlers = append(handlers, e.middlewares...)handlers = append(handlers, handler)ctx.Handlers = handlersctx.Next()
}func (e *Engine) Use(middlewares ...context.HandleFunc) {for _, middleware := range middlewares {e.middlewares = append(e.middlewares, middleware)}
}func (e *Engine) POST(path string, handler context.HandleFunc) {key := makeHandlerKey(http.MethodPost, path)e.handlers[key] = handler
}func (e *Engine) GET(path string, handler context.HandleFunc) {key := makeHandlerKey(http.MethodGet, path)e.handlers[key] = handler
}func (e *Engine) Run(addr string) error {return http.ListenAndServe(addr, e)
}func makeHandlerKey(method, path string) string {return method + constant.Separator + path
}

5 example.go

package mainimport ("fmt""mini_gee/context""mini_gee/engine""time"
)func main() {e := engine.New()e.Use(func(context *context.Context) {start := time.Now()defer func() {fmt.Println(context.Method, context.Path, time.Since(start).Microseconds(), "us")}()context.Next()})e.POST("/hello", func(context *context.Context) {name, ok := context.GetPostForm("name")if !ok {context.JSON(200, map[string]interface{}{"code":    1,"message": "field name not found",})return}context.JSON(200, map[string]interface{}{"code":    1,"message": "hello " + name,"data":    name,})})e.GET("/bonjour", func(context *context.Context) {food, ok := context.GetQuery("food")if !ok {context.JSON(200, map[string]interface{}{"code":    1,"message": "field food not found",})return}context.String(200, food)})e.GET("/test_error", func(context *context.Context) {var arr []intfmt.Println(arr[10])})if err := e.Run(":9090"); err != nil {panic(err)}
}

6 docker部署

6.1 编写dockerfile

FROM ubuntu
ENV MYPATH=/usr/local
WORKDIR $MYPATH
ADD main ./
CMD ./main

6.2 定制镜像

在这里插入图片描述
在这里插入图片描述

6.3 后台启动容器

在这里插入图片描述

7 测试

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/396671.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WINDOWS核心编程-----3章,内核对象,是现在不同账号下测试

系列文章目录 终端服务命名空间中内核对象的测试程序 TerminalService程序需要用登录不同的windows账号同时运行。才能看出效果 建议测试流程 1&#xff0c;先登录windows账号A&#xff0c;运行两个本程序实例 2&#xff0c;保持上述两个实例人在运行中&#xff0c;在登陆wind…

Vue3 搭建前端工程,并使用idea配置项目启动

1 下载node.js 先下载 node.js LTS 并安装&#xff1a;node.js 的 npm&#xff0c;用于管理前端项目包依赖&#xff0c;这里以 14.17.3 这个版本为例。如果已经安装过 node.js&#xff0c;可以在设置中找到应用&#xff0c;点进去搜索 node.js 即可卸载 node.js 14.17.3 安装…

C语言典型例题32

《C程序设计教程&#xff08;第四版&#xff09;——谭浩强》 习题2.9 编程序用getchar函数读入两个字符给c1&#xff0c;c2&#xff0c;然后分别用putchar函数和printf函数输出这两个字符。 &#xff08;1&#xff09;变量c1&#xff0c;c2应该定义为字符型或者整型吗&#x…

Flutter 学习之旅

本文只针对个人学习所遇问题&#xff0c;以及解决方案进行记录&#xff0c;不深刨原理。 不深刨原理是因为我也才开始学习&#xff0c;讲不明白&#xff0c;有可能还误导大家 &#xff0c;希望多多包涵。 问题一&#xff1a; 如何通过appBar去设置状态栏字体颜色以及状态栏透…

LLM - 使用 HuggingFace + Ollama 部署最新大模型 (GGUF 格式 与 Llama 3.1)

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/141028040 免责声明&#xff1a;本文来源于个人知识与公开资料&#xff0c;仅用于学术交流&#xff0c;欢迎讨论&#xff0c;不支持转载。 Ollama…

【Linux】Ubuntu20.04系统中能在命令行ping通百度等网站,而在浏览器中不能上网的问题解决方法

今天离开学校&#xff0c;在家中打开ubuntu系统准备上网&#xff0c;发现浏览器打不开&#xff0c;但是QQ是可以发消息的&#xff0c;证明WIFI应该是没有问题的&#xff0c;但是谷歌和火狐浏览器就是打不开网址&#xff0c;很奇怪&#xff01; 先检查我们Linux能不能ping通 开一…

基于Jakarta,TypeScript,Golong的国密SM2、3、4

文章目录 前言一. Jakarta代码二. TypeScript三.golang 前言 最近还要深度研究hutools底层实现&#xff0c;一定要搞透澈&#xff0c;本章将会是持续更新 所有密钥由Jakarta统一生成&#xff0c;因为没测试其他语言生成是否可以 参考资料&#xff1a; Java代码实现SM2算法以及…

整理 钢琴 基础知识

大普表和钢琴键盘对照表 一 大普表和钢琴键盘对照表 二 五线谱、键位、左右手 八分音符 坐姿 手型

机器学习——支持向量机(SVM)(1)

目录 一、认识SVM 1. 基本介绍 2. 支持向量机分类器目标 二、线性SVM分类原理&#xff08;求解损失&#xff09; 三、重要参数 1. kernel&#xff08;核函数&#xff09; 2 .C&#xff08;硬间隔与软间隔&#xff09; 四、sklearn中的支持向量机&#xff08;自查&#…

使用Adobe Photoshop CS5给图片加水印

使用Adobe Photoshop CS5给图片加水印 前言1.我这里使用的是Adobe Photoshop CS52.新建空白画布3.写入水印内容4.按 Ctrl T 将其倾斜5.右键图层选择“混合选项”6.选择描边&#xff0c;颜色选择灰色7.效果如下8.填充选择0&#xff0c;不透明度选择75%9.打开编辑&#xff0c;选…

transformer中编码器之间是串行还是并行的;算力共享中,transformer实现编码器并行运行,怎么进行聚合的

目录 transformer中编码器之间是串行还是并行的 1. 编码器结构的独立性 2. 编码器内部的并行处理 3. 编码器之间的数据流 4. 训练阶段的并行性 算力共享中,transformer实现编码器并行运行,怎么进行聚合的 编码器并行运行的实现 编码器的输出聚合 举例说明 transform…

对 Go 语言中循环屏障 CyclicBarrier 的理解

同步屏障 (Barrier) 是并发编程中的一种同步方法。对于一组 goroutine ,程序中的一个同步屏障意味着任何 goroutine 执行到此后都必须等待,直到所有的 goroutine 都达到此点才可继续执行下文。 Barrier 无论是翻译成屏障、障碍还是栅栏,都很形象,就是一道拦截坝,拦截一组对…

国内大量家用路由器惨遭DNS劫持,你中招了吗?

近期&#xff0c;D妹收到不少用户反馈&#xff0c;在访问网站或APP时都遭遇了访问失败的问题。经深入排查&#xff0c;我们监测到大量家用路由器的DNS解析配置被篡改&#xff0c;从而影响到了正常的网站和APP访问。 该情况于2024年5月开始出现&#xff0c;于8月5日集中爆发达到…

图像变换算法

1.1 傅里叶变换 (Fourier Transform) 介绍 傅里叶变换是一种数学变换&#xff0c;用于将图像从空间域转换到频率域。它广泛应用于图像去噪和滤波。 原理 傅里叶变换将图像表示为频率成分的叠加&#xff0c;使得频率成分可以独立处理。通过对频率成分的分析和处理&#xff0…

【登录扫码】--集成企业微信

背景&#xff1a; 在系统的登录流程中&#xff0c;我们引入了一种创新的扫码登录方式&#xff0c;旨在提升用户体验与安全性。此流程的核心在于通过生成并扫描二维码来实现快速、便捷的登录认证 调用流程详细说明&#xff1a; 扫码登录选择&#xff1a;用户首先访问系统登录页面…

STM32的SDIO接口详解

目录 1. 定义与兼容性 2. SDIO时钟 3. SDIO命令与响应 4. SDIO块数据传输 5. SDIO控制器的硬件结构 6.代码实现 1.SD初始化 2.测试SD卡的读取 3.测试SD卡的写入 STM32的SDIO&#xff08;Secure Digital Input/Output&#xff0c;安全数字输入输出&#xff09;接口是一…

010集——按值传递、按引用传递等方法——C#学习笔记

按值传递参数 这是参数传递的默认方式。在这种方式下&#xff0c;当调用一个方法时&#xff0c;会为每个值参数创建一个新的存储位置。 实际参数的值会复制给形参&#xff0c;实参和形参使用的是两个不同内存中的值。所以&#xff0c;当形参的值发生改变时&#xff0c;不会影…

Flask+LayUI开发手记(一):LayUI表格的前端数据分页展现

用数据表格table展示系统数据&#xff0c;是LayUI的基本功能&#xff0c;编码十分简单&#xff0c;就是通过table.render()渲染&#xff0c;把属性配置好就OK了&#xff0c;十分方便&#xff0c;功能也十分强大。 不过&#xff0c;在实现时&#xff0c;把table的有个功能却理解…

ue4.27 C++ 解析内容为json的字符串

json字符串为 R"({"x": -1870.0, "y": -11400.0})"&#xff0c;里面内容是个json对象。 const FString& Message R"({"x": -1870.0, "y": -11400.0})"; TSharedRef<TJsonReader<>> Reader TJs…

Java Nacos与Gateway的使用

Java系列文章目录 IDEA使用指南 Java泛型总结&#xff08;快速上手详解&#xff09; Java Lambda表达式总结&#xff08;快速上手详解&#xff09; Java Optional容器总结&#xff08;快速上手图解&#xff09; Java 自定义注解笔记总结&#xff08;油管&#xff09; Jav…