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     ```