trpc.group/trpc-go/trpc-go@v1.0.3/internal/httprule/README.zh_CN.md (about) 1 # 关于 HttpRule 2 3 要支持 RESTful API,其难点在于如何将 Proto Message 里面的各个字段映射到 HTTP 请求/响应中。这种映射关系当然不是原生就存在的。 4 5 所以,我们需要定义一种规则,来规定具体如何映射,这种规则,就是 ***HttpRule*** : 6 7 在 pb 文件中,我们通过 Option 选项:**trpc.api.http** 来指定 HttpRule,映射时 rpc 请求 message 里的“叶子”字段分**三种**情况处理: 8 9 1. 字段被 HttpRule 的 url path 引用:HttpRule 的 url path 引用了 rpc 请求 message 中的一个或多个字段,则 rpc 请求 message 的这些字段就通过 url path 传递。但这些字段必须是原生基础类型的非数组字段,不支持消息类型的字段,也不支持数组字段。 10 11 2. 字段被 HttpRule 的 body 引用:HttpRule 的 body 里指明了映射的字段,则 rpc 请求 message 的这些字段就通过 http 请求 body 传递。 12 13 3. 其他字段:其他字段都会自动成为 url 查询参数,而且如果是 repeated 字段,则支持同一个 url 查询参数多次查询。 14 15 **补充**: 16 17 1. 如果 HttpRule 的 body 里未指明字段,用 "*" 来定义,则没有被 url path 绑定的每个请求 message 字段都通过 http 请求的 body 传递。 18 19 2. 如果 HttpRule 的 body 为空,则没有被 url path 绑定的每个请求 message 字段都会自动成为 url 查询参数。 20 21 ## 关于 httprule 包 22 23 易见,HttpRule 的处理难点在于 url path 匹配。 24 25 首先,RESTful 请求的 url path 需要用一个模板统一起来: 26 27 ```Go 28 Template = "/" Segments [ Verb ] ; 29 Segments = Segment { "/" Segment } ; 30 Segment = "*" | "**" | LITERAL | Variable ; 31 Variable = "{" FieldPath [ "=" Segments ] "}" ; 32 FieldPath = IDENT { "." IDENT } ; 33 Verb = ":" LITERAL ; 34 ``` 35 36 即 HttpRule 里的 url path 都必须按照这个模板。 37 38 ```httprule```包提供 ```Parse``` 方法可以将任意 HttpRule 里指定的 url path 解析为模板 ```PathTemplate``` 类型。 39 40 ```PathTemplate``` 类提供一个 ```Match``` 方法,可以从真实的 http 请求 url path 里匹配到变量的值。 41 42 ***举例一:*** 43 44 如果 pb Option **trpc.api.http** 中指定的 HttpRule url path 为:```/foobar/{foo}/bar/{baz}```,其中 ```foo``` 和 ```baz``` 为变量。 45 46 解析到模板: 47 48 ```Go 49 tpl, _ := httprule.Parse("/foobar/{foo}/bar/{baz}") 50 ``` 51 52 匹配一个 http 请求中的 url path: 53 54 ```Go 55 captured, _ := tpl.Match("/foobar/x/bar/y") 56 ``` 57 58 则: 59 60 ```Go 61 reflect.DeepEqual(captured, map[string]string{"foo":"x", "baz":"y"}) 62 ``` 63 64 ***举例二:*** 65 66 如果 pb Option **trpc.api.http** 中指定的 HttpRule url path 为:```/foobar/{foo=x/*}```,其中 ```foo``` 为变量。 67 68 解析到模板: 69 70 ```Go 71 tpl, _ := httprule.Parse("/foobar/{foo=x/*}") 72 ``` 73 74 匹配一个 http 请求中的 url path: 75 76 ```Go 77 captured, _ := tpl.Match("/foobar/x/y") 78 ``` 79 80 则: 81 82 ```Go 83 reflect.DeepEqual(captured, map[string]string{"foo":"x/y"}) 84 ```