不借助框架实现Go路由参数匹配 需构建多少个路由处理器
结论
你可以根据实现需求灵活选择两种方案,最低仅需1个通用路由处理器,更易维护的写法是编写2个独立的业务路由处理器:
方案1:2个独立业务处理器(更推荐)
- 先实现一个通用的路径参数解析工具,用来从URL路径中提取
{tenderReference}和{venderCode}两个参数 - 分别为两个业务路由编写独立的处理器函数,每个处理器内先调用参数解析工具拿到参数,初始化Tender结构体后调用对应的
readWrite/readOnly方法 - 最后把两个处理器绑定对应的路径规则注册到路由中即可
方案2:1个通用分发处理器(代码量更少)
- 仅编写一个全局处理器,在处理器内先判断当前请求路径匹配哪个路由规则,提取参数后根据路径的操作类型(
readWrite/readOnly)决定调用Tender的对应方法 - 这种方式只需要1个处理器,但逻辑耦合度更高,后续新增路由时维护成本会上升
简单实现示例
import ( "fmt" "net/http" "strconv" "strings" ) type Tender struct { tenderReference string venderCode int } func (t Tender) readWrite() { fmt.Printf("Tender %s is ready for vendor %d to review and submit\n", t.tenderReference, t.venderCode) } func (t Tender) readOnly(w http.ResponseWriter, r *http.Request) { fmt.Printf("Tender %s already submitted by vender %d\n", t.tenderReference, t.venderCode) } // 通用路径参数解析函数 func parseParams(pattern, path string) (map[string]string, bool) { patternParts := strings.Split(strings.Trim(pattern, "/"), "/") pathParts := strings.Split(strings.Trim(path, "/"), "/") if len(patternParts) != len(pathParts) { return nil, false } params := make(map[string]string) for i, part := range patternParts { if strings.HasPrefix(part, "{") && strings.HasSuffix(part, "}") { paramName := strings.TrimSuffix(strings.TrimPrefix(part, "{"), "}") params[paramName] = pathParts[i] } else if part != pathParts[i] { return nil, false } } return params, true } // 两个独立处理器实现 func readWriteHandler(w http.ResponseWriter, r *http.Request) { params, ok := parseParams("/api/tender/readWrite/{tenderReference}/vendor/{venderCode}", r.URL.Path) if !ok { http.NotFound(w, r) return } venderCode, err := strconv.Atoi(params["venderCode"]) if err != nil { http.Error(w, "无效的供应商编码", http.StatusBadRequest) return } tender := Tender{ tenderReference: params["tenderReference"], venderCode: venderCode, } tender.readWrite() w.WriteHeader(http.StatusOK) } func readOnlyHandler(w http.ResponseWriter, r *http.Request) { params, ok := parseParams("/api/tender/readOnly/{tenderReference}/vendor/{venderCode}", r.URL.Path) if !ok { http.NotFound(w, r) return } venderCode, err := strconv.Atoi(params["venderCode"]) if err != nil { http.Error(w, "无效的供应商编码", http.StatusBadRequest) return } tender := Tender{ tenderReference: params["tenderReference"], venderCode: venderCode, } tender.readOnly(w, r) w.WriteHeader(http.StatusOK) } // 注册路由启动服务 func main() { http.HandleFunc("/api/tender/readWrite/", readWriteHandler) http.HandleFunc("/api/tender/readOnly/", readOnlyHandler) http.ListenAndServe(":8080", nil) }
内容的提问来源于stack exchange,提问作者Hasan A Yousef
相关产品推荐
相关产品推荐

