# jk **Repository Path**: ruige_fun/jk ## Basic Information - **Project Name**: jk - **Description**: 路由:net/http默认的。 只是在官方基础上做一层封装,使其支持一些常用的方法。 支持中间件。 支持自定义Validator表单校验。 支持各种读取请求信息方法。 支持各种写入响应体方法。 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2023-11-24 - **Last Updated**: 2025-08-26 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 介绍 建议版本go版本 >= 1.23.0 # 安装教程 ``` go get gitee.com/ruige_fun/jk ``` # 尽量只使用官方包 - 路由:net/http默认的。 - 只是在官方基础上做一层封装,使其支持一些常用的方法。 - 支持中间件。 - 支持各种读取请求信息方法。 - 支持各种写入响应体方法。 # 更多上下文方法 请访问 https://gitee.com/ruige_fun/rht - GetIP 获取相对真实客户端IP地址 - ReadBody 读取请求体 - ReadQuery 读取请求参数,并且绑定到结构体,并且进行表单校验 - ReadForm、ReadPostForm、ReadJson、ReadXml 读取表单,并且绑定到结构体,并且进行表单校验 - GetFormFile、GetFormFileSave、SaveFormFile 获取表单文件 - WriteStdJSON、WriteStdXML、WriteString、WriteBytes 等等写入响应体方法 # 常用方法 ## 基本使用 ````go package main import ( "gitee.com/ruige_fun/jk" "net/http" "time" ) func main() { mux := jk.NewServeMux() mux.HandleFunc("GET /ping", func(c jk.Context)jk.Error { _ = c.Response().WriteStdJSON(http.StatusOK, "", time.Now().String(), nil) return nil }) _ = http.ListenAndServe(":8080", mux) } ```` 访问 http://127.0.0.1:8080/ping ````json {"code":200,"msg":"","data":{"data":"2025-06-14 18:35:17.4507441 +0800 CST m=+5.791581201","other":null}} ```` ## 中间件和上下文传值 ````go package main import ( "gitee.com/ruige_fun/jk" "log" "net/http" "time" ) func main() { mux := jk.NewServeMux() app := mux.Use(printLog0).Use(printLog1) app.HandleFunc("GET /ping", func(c jk.Context)jk.Error { _ = c.Response().WriteStdJSON(http.StatusOK, "", time.Now().String(), nil) return nil }) _ = http.ListenAndServe(":8080", mux) } func printLog0(next jk.HandlerFunc) jk.HandlerFunc { return func(c jk.Context)jk.Error { now := time.Now() log.Println("printLog0开始") err := next(c) log.Println("printLog0结束", c.Request().GetIP(), c.Request().GetMethod(), c.Request().GetURI(), time.Since(now), "uid =", c.Store().GetInt("uid")) return err } } func printLog1(next jk.HandlerFunc) jk.HandlerFunc { return func(c jk.Context)jk.Error { now := time.Now() log.Println("printLog1开始") c.Store().SetInt("uid", 123) err := next(c) log.Println("printLog1结束", c.Request().GetIP(), c.Request().GetMethod(), c.Request().GetURI(), time.Since(now), "uid =", c.Store().GetInt("uid")) return err } } ```` 访问 http://127.0.0.1:8080/ping ````json {"code":200,"msg":"","data":{"data":"2025-06-14 18:42:54.045338 +0800 CST m=+13.220488901","other":null}} ```` 控制台输出 ````text 2025/06/14 18:42:54 printLog0开始 2025/06/14 18:42:54 printLog1开始 2025/06/14 18:42:54 printLog1结束 127.0.0.1 GET /ping 0s uid = 123 2025/06/14 18:42:54 printLog0结束 127.0.0.1 GET /ping 0s uid = 123 ```` ## 表单绑定&校验 ````go package main import ( "gitee.com/ruige_fun/jk" "net/http" ) func main() { mux := jk.NewServeMux() mux.HandleFunc("GET /ping", ping) _ = http.ListenAndServe(":8080", mux) } type pPing struct { ID uint `json:"id" form:"id" validate:"required,min=1"` Name string `json:"name" form:"name" validate:"required,min=1"` } func ping(c jk.Context)jk.Error { var p pPing if err := c.Request().ReadQuery(&p); err != nil { return jk.ErrParams } _ = c.Response().WriteStdJSON(http.StatusOK, "", p, nil) return nil } ```` 访问 http://127.0.0.1:8080/ping?id=1&name=瑞哥 ````json {"code":200,"msg":"","data":{"data":{"id":1,"name":"瑞哥"},"other":null}} ```` ## sse事件流 ````go package main import ( "gitee.com/ruige_fun/jk" "net/http" "time" ) func main() { mux := jk.NewServeMux() mux.HandleFunc("POST /sse", sseHandler) _ = http.ListenAndServe(":8080", mux) } func sseHandler(c jk.Context)jk.Error { sse, err := jk.NewSSE(c) if err != nil { return jk.NewHttpError(http.StatusOK, http.StatusInternalServerError, "NewSSE error") } ticker := time.NewTicker(time.Second) for { select { case <-c.Done(): return nil case <-ticker.C: _ = sse.SendData("Hello") } } } ```` ## websocket ````go package main import ( "gitee.com/ruige_fun/jk" "github.com/gorilla/websocket" "log" "net/http" ) func main() { mux := jk.NewServeMux() mux.HandleFunc("/ws", ws) _ = http.ListenAndServe(":8080", mux) } var upgrader = websocket.Upgrader{CheckOrigin: func(r *http.Request) bool { return true }} func ws(c jk.Context)jk.Error { conn, err := upgrader.Upgrade(c.Response().ResponseWriter(), c.Request().Request(), nil) if err != nil { log.Println("Upgrade err :", err) return jk.ErrUpgradeRequired } defer conn.Close() for { mt, msg, err := conn.ReadMessage() if err != nil { log.Println("ReadMessage err :", err) break } log.Println("recv :", string(msg)) err = conn.WriteMessage(mt, msg) if err != nil { log.Println("WriteMessage err :", err) break } } return nil } ```` 访问 ws://127.0.0.1:8080/ws ## 静态文件服务 ### 使用官方包文件服务 ````go package main import ( "gitee.com/ruige_fun/jk" "net/http" ) func main() { mux := jk.NewServeMux() mux.HandleFunc("/static/", fileServer()) _ = http.ListenAndServe(":8080", mux) } func fileServer() func(c jk.Context)jk.Error { prefix := http.StripPrefix("/static", http.FileServer(http.Dir("./"))) return func(c jk.Context)jk.Error { prefix.ServeHTTP(c.Response().ResponseWriter(), c.Request().Request()) return nil } } ```` 访问 http://127.0.0.1:8080/static/ ### 自定义文件下载服务 ````go package main import ( "gitee.com/ruige_fun/jk" "net/http" "os" "path/filepath" "strings" ) func main() { mux := jk.NewServeMux() mux.HandleFunc("/static/", fileServer) _ = http.ListenAndServe(":8080", mux) } func fileServer(c jk.Context)jk.Error { filePath := strings.TrimPrefix(c.Request().GetPath(), "/static") file, err := os.Open(filepath.Join("./", filePath)) if err != nil { return jk.Err404 } defer file.Close() stat, err := file.Stat() if err != nil { return jk.Err404 } c.Response().HeaderSet(http.CanonicalHeaderKey("Content-Disposition"), "attachment; filename=\""+stat.Name()+"\"") http.ServeContent(c.Response().ResponseWriter(), c.Request().Request(), stat.Name(), stat.ModTime(), file) return nil } ```` ### 自定义文件下载限速 ````go package main import ( "gitee.com/ruige_fun/jk" "io" "net/http" "os" "path/filepath" "strings" "time" ) func main() { mux := jk.NewServeMux() mux.HandleFunc("/static/", fileServer) _ = http.ListenAndServe(":8080", mux) } func fileServer(c jk.Context)jk.Error { filePath := strings.TrimPrefix(c.Request().GetPath(), "/static") file, err := os.Open(filepath.Join("./", filePath)) if err != nil { return jk.Err404 } defer file.Close() stat, err := file.Stat() if err != nil { return jk.Err404 } c.Response().HeaderSet(http.CanonicalHeaderKey("Content-Disposition"), "attachment; filename=\""+stat.Name()+"\"") ticker := time.NewTicker(time.Second) //设置每个刻度多长时间。 defer ticker.Stop() http.ServeContent(c.Response().ResponseWriter(), c.Request().Request(), stat.Name(), stat.ModTime(), NewReadSeeker(file, ticker, 100*1024)) return nil } func NewReadSeeker(file *os.File, ticker *time.Ticker, rateSize int64) io.ReadSeeker { return &_File{file: file, rateSize: rateSize, ticker: ticker} } var _ io.ReadSeeker = new(_File) type _File struct { file *os.File tempSize int64 rateSize int64 //大概值,这种方式无法做到准确值。 ticker *time.Ticker } func (f *_File) Read(p []byte) (n int, err error) { if f.tempSize >= f.rateSize { <-f.ticker.C f.tempSize = 0 } n, err = f.file.Read(p) if n > 0 { f.tempSize += int64(n) } return n, err } func (f *_File) Seek(offset int64, whence int) (int64, error) { return f.file.Seek(offset, whence) } ````