为 gRPC JSON 转码配置 HTTP 和 JSON
注意
此版本不是本文的最新版本。 对于当前版本,请参阅此文的 .NET 8 版本。
警告
此版本的 ASP.NET Core 不再受支持。 有关详细信息,请参阅 .NET 和 .NET Core 支持策略。 对于当前版本,请参阅此文的 .NET 8 版本。
gRPC JSON 转码从 gRPC 方法创建 RESTful JSON Web API。 它使用注释和选项来自定义 RESTful API 如何映射到 gRPC 方法。
HTTP 规则
gRPC 方法必须在支持转码之前使用 HTTP 规则进行注释。 HTTP 规则包含将 gRPC 方法作为 RESTful API 调用的信息,例如 HTTP 方法和路由。
import "google/api/annotations.proto";
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {
option (google.api.http) = {
get: "/v1/greeter/{name}"
};
}
}
HTTP 规则:
- 是 gRPC 方法的注释。
- 由名称
google.api.http
标识。 - 从
google/api/annotations.proto
文件导入。google/api/http.proto
和google/api/annotations.proto
文件需要位于项目中。
注意
指向 .NET 参考源的文档链接通常会加载存储库的默认分支,该分支表示针对下一个 .NET 版本的当前开发。 若要为特定版本选择标记,请使用“切换分支或标记”下拉列表。 有关详细信息,请参阅如何选择 ASP.NET Core 源代码的版本标记 (dotnet/AspNetCore.Docs #26205)。
HTTP 方法
通过将路由设置为匹配的 HTTP 方法字段名称来指定 HTTP 方法:
get
put
post
delete
patch
custom
字段适用于其他 HTTP 方法。
在以下示例中,CreateAddress
方法使用指定的路由映射到 POST
:
service Address {
rpc CreateAddress (CreateAddressRequest) returns (CreateAddressReply) {
option (google.api.http) = {
post: "/v1/address",
body: "*"
};
}
}
路由
gRPC JSON 转码路由支持路由参数。 例如,路由中的 {name}
绑定到请求消息上的 name
字段。
若要绑定嵌套消息上的字段,请指定字段的路径。 在以下示例中,{params.org}
绑定到 IssueParams
消息上的 org
字段:
service Repository {
rpc GetIssue (GetIssueRequest) returns (GetIssueReply) {
option (google.api.http) = {
get: "/{apiVersion}/{params.org}/{params.repo}/issue/{params.issueId}"
};
}
}
message GetIssueRequest {
int32 api_version = 1;
IssueParams params = 2;
}
message IssueParams {
string org = 1;
string repo = 2;
int32 issueId = 3;
}
转码路由和 ASP.NET Core 路由具有类似的语法和功能集。 但是,转码不支持某些 ASP.NET Core 路由功能。 其中包括:
请求正文
转码将请求正文 JSON 反序列化为请求消息。 body
字段指定 HTTP 请求正文如何映射到请求消息。 值是其值映射到 HTTP 请求正文的请求字段的名称,或用于映射所有请求字段的 *
。
在以下示例中,HTTP 请求正文反序列化为 address
字段:
service Address {
rpc AddAddress (AddAddressRequest) returns (AddAddressReply) {
option (google.api.http) = {
post: "/{apiVersion}/address",
body: "address"
};
}
}
message AddAddressRequest {
int32 api_version = 1;
Address address = 2;
}
message Address {
string street = 1;
string city = 2;
string country = 3;
}
查询参数
可以使用 HTTP 查询参数设置请求消息中未被路由参数或请求正文绑定的任何字段。
service Repository {
rpc GetIssues (GetIssuesRequest) returns (GetIssuesReply) {
option (google.api.http) = {
get: "/v1/{org}/{repo}/issue"
};
}
}
message GetIssuesRequest {
string org = 1;
string repo = 2;
string text = 3;
PageParams page = 4;
}
message PageParams {
int32 index = 1;
int32 size = 2;
}
在上面的示例中:
org
和repo
字段是从路由参数绑定的。- 其他字段(如
text
和page
中的嵌套字段)可以从查询字符串绑定:?text=value&page.index=0&page.size=10
响应正文
默认情况下,转码会将整个响应消息序列化为 JSON。 response_body
字段允许序列化响应消息的子集。
service Address {
rpc GetAddress (GetAddressRequest) returns (GetAddressReply) {
option (google.api.http) = {
get: "/v1/address/{id}",
response_body: "address"
};
}
}
message GetAddressReply {
int32 version = 1;
Address address = 2;
}
message Address {
string street = 1;
string city = 2;
string country = 3;
}
在上述示例中,address
字段作为 JSON 被序列化到响应正文。
规范
有关如何自定义 gRPC 转码的详细信息,请参阅 HttpRule 规范。
自定义 JSON
使用 Protobuf 规范中的 JSON 映射在消息和 JSON 之间进行双向转换。 Protobuf 的 JSON 映射是一种在 JSON 和 Protobuf 之间转换的标准化方法,所有序列化都遵循这些规则。
但是,gRPC JSON 转码提供了一些有限选项,可以使用 GrpcJsonSettings 自定义 JSON,如下表所示。
选项 | 默认值 | 说明 |
---|---|---|
IgnoreDefaultValues | false |
如果设置为 true ,则在序列化过程中将忽略具有默认值的字段。 |
WriteEnumsAsIntegers | false |
如果设置为 true ,则枚举值将作为整数(而不是字符串)写入。 |
WriteInt64sAsStrings | false |
如果设置为 true ,则 Int64 和 UInt64 值将作为字符串(而不是数字)写入。 |
WriteIndented | false |
如果设置为 true ,JSON 将使用整齐打印写入。 此选项不会影响流式处理方法,该方法写入以行分隔的 JSON 消息并且无法使用整齐打印。 |
builder.Services.AddGrpc().AddJsonTranscoding(o =>
{
o.JsonSettings.WriteIndented = true;
});
在 .proto
文件中,json_name
字段选项在序列化为 JSON 时会自定义字段的名称,如以下示例所示:
message TestMessage {
string my_field = 1 [json_name="customFieldName"];
}
转码不支持高级 JSON 自定义。 需要精确 JSON 结构控制的应用应考虑使用 ASP.NET Core Web API。