gRPC:HttpRule

本文介绍了gRPC与HTTP方法的映射关系。gRPC是Google基于rpc开发的新功能,可跨语言通信,也能通过HTTP请求访问服务。HttpRule规定了两者的映射规则,包括简单Url模板、请求消息参数处理等。此外,还分享了遇到的问题及总结。

前言

这个是在定义gRPC服务时遇到的知识点。HttpRule定义了gRPC方法与HTTP方法的映射关系,具体来说,是请求和相应之间的对应关系。这篇博文仅作简单对应关系的介绍,重在使用,不深究原理。
另:本人还是新手,如有描述上的不当请不吝赐教。

一、gRPC

gRPC是Google在rpc基础上开发的新功能。RPC,远程过程调用,简单来说就是可以远程访问其他服务器上的服务。最直白的例子就是:我有两个主机A和B。A中启动了一个服务;B可以通过RPC的方式调用A中的服务。当然,RPC可以不是两台主机间的描述,同一台主机上两个进程也属于远程过程调用。
gRPC的使用方法:

  • 定义proto文件;
  • 下载grpc,生成代码;
  • 编写服务端代码:主要是对于定义的服务的实现;
  • 编写grpc服务器代码:包括在哪个端口监听,等功能;
  • 编写客户端代码:访问服务端方法。

gRPC的优点:

  • 是跨语言的;服务端和客户端可以使用不同的程序语言,也可进行通信;
  • 也可以通过HTTP请求,访问服务。

这里就涉及到http方法和grpc方法之间的映射关系。

二、HttpRule

在定义proto文件时,考虑到grpc需要通过http方法进行访问,因此在grpc方法中需要定义与http方法的映射关系。HttpRule即规定了两者映射规则。先简单总结如下:

  • 通过google.api.http标志与http方法间的映射;
  • 通过additional_bindings与多个http方法实现映射;
  • 通过url模板定义映射关系;
  • url模板可以指定grpc请求消息中的多个参数;
  • 在没有定义请求体时,grpc请求消息中没有被绑定到url模板中的参数会自动成为http查询参数;
  • 请求体值为*时,没有映射到url模板的所有参数都在请求体中;此时不允许http查询参数;

这里提到的http查询参数,即在url中通过?name=jason&sex=male定义的查询参数。
url模板中定义的参数,即在映射规则中写的url路径。

1. 简单Url模板

service Messaging {
  rpc GetMessage(GetMessageRequest) returns (Message) {
    option (google.api.http) = {
        get: "/v1/{name=messages/*}"
    };
  }
}
message GetMessageRequest {
  string name = 1; // Mapped to URL path.
}
message Message {
  string text = 1; // The resource content.
}

这里的/v1/{name=messages/*}为url模板。它定义了在http请求方法中,v1后的内容与请求消息GetMessageRequest的name属性之间的映射关系:

HTTPgRPC
GET /v1/messages/123456GetMessage(name: “messages/123456”)

2. 没有绑定在url模板中的请求消息

service Messaging {
  rpc GetMessage(GetMessageRequest) returns (Message) {
    option (google.api.http) = {
        get:"/v1/messages/{message_id}"
    };
  }
}
message GetMessageRequest {
  message SubMessage {
    string subfield = 1;
  }
  string message_id = 1; // Mapped to URL path.
  int64 revision = 2;    // Mapped to URL query parameter `revision`.
  SubMessage sub = 3;    // Mapped to URL query parameter `sub.subfield`.
}

这里的url请求模板:/v1/messages/{message_id},定义了http方法中参数与请求消息GetMEssageRequest的message_id属性的映射关系。而请求消息中的revision和sub没有定义在模板中。在实际请求时,通过http请求参数定义:

HTTPgRPC
GET /v1/messages/123456?revision=2&sub.subfield=fooGetMessage(message_id: “123456” revision: 2 sub: SubMessage(subfield: “foo”))

3. body域

service Messaging {
  rpc UpdateMessage(UpdateMessageRequest) returns (Message) {
    option (google.api.http) = {
      patch: "/v1/messages/{message_id}"
      body: "message"
    };
  }
}
message UpdateMessageRequest {
  string message_id = 1; // mapped to the URL
  Message message = 2;   // mapped to the body
}
HTTPgRPC
PATCH /v1/messages/123456 { “text”: “Hi!” }UpdateMessage(message_id: “123456” message { text: “Hi!” })

4. body域取值为*

service Messaging {
  rpc UpdateMessage(Message) returns (Message) {
    option (google.api.http) = {
      patch: "/v1/messages/{message_id}"
      body: "*"
    };
  }
}
message Message {
  string message_id = 1;
  string text = 2;
}

可实现如下映射关系:

HTTPgRPC
PATCH /v1/messages/123456 { “text”: “Hi!” }UpdateMessage(message_id: “123456” text: “Hi!”)

三、遇到的问题

很奇怪的是,遇到了一个不知道该怎么写http请求的grpc方法。
gRPC方法定义如下:

rpc Invalidate(InvalidateRequest) returns (Response) {
    option (google.api.http) = {
        post: "/v1/thing:invalidate"
    };
}

message InvalidateRequest{
    // Required. 
    string url= 1 [(validator.field) = {string_not_empty: true}];
    // Required. as input.
    repeated Message input_messages = 2 [(validator.field) = {repeated_count_min: 1}];
}
message Message {
    // Required. 
    string version = 1;
    // Optional. 
    repeated int64 target_ids = 2;
}

这里的Invalidate方法建立了与http post方法的映射;同时没有提供body域。因此参数都通过url和http查询参数来传递。但。请求方法失败。
猜测: 莫非是构造的input_messages 参数错误?
如有知道的大侠望不吝赐教。

四、总结

本篇主要是介绍了定义gRPC和http方法映射的方法。

参考

  1. HttpRule
要调用 `AsyncrequestBiStream` 函数,需要准备好该函数所需的参数,即 `::grpc::ClientContext*`、`::grpc::CompletionQueue*` 和 `void*` 类型的参数。以下是一个示例代码,展示了如何调用这个函数: ```cpp #include <grpcpp/grpcpp.h> #include "com/sendinfo/ticketing/verification/device/gateway/service/grpc/v1/your_service.pb.h" #include "com/sendinfo/ticketing/verification/device/gateway/service/grpc/v1/your_service.grpc.pb.h" // 假设这是你的服务类 class YourServiceClient { public: std::unique_ptr< ::grpc::ClientAsyncReaderWriter< ::com::sendinfo::ticketing::verification::device::gateway::service::grpc::v1::Payload, ::com::sendinfo::ticketing::verification::device::gateway::service::grpc::v1::Payload>> AsyncrequestBiStream(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq, void* tag) { // 这里是函数的具体实现 // 为了示例,我们简单返回一个空的 unique_ptr return std::unique_ptr< ::grpc::ClientAsyncReaderWriter< ::com::sendinfo::ticketing::verification::device::gateway::service::grpc::v1::Payload, ::com::sendinfo::ticketing::verification::device::gateway::service::grpc::v1::Payload>>(); } }; int main() { YourServiceClient client; // 创建 ClientContext ::grpc::ClientContext context; // 创建 CompletionQueue ::grpc::CompletionQueue cq; // 创建 tag void* tag = static_cast<void*>(new int(1)); // 调用 AsyncrequestBiStream 函数 auto stream = client.AsyncrequestBiStream(&context, &cq, tag); // 后续可以使用 stream 进行双工流操作 return 0; } ``` ### 代码解释 1. **参数准备**: - `::grpc::ClientContext`:用于管理 RPC 调用的上下文信息,如超时时间、元数据等。 - `::grpc::CompletionQueue`:用于异步操作的完成通知。 - `void* tag`:用于标识异步操作的标签,在完成通知时可以根据这个标签来区分不同的操作。 2. **函数调用**: - 通过创建的 `YourServiceClient` 对象调用 `AsyncrequestBiStream` 函数,并传入准备好的参数。 3. **返回值使用**: - 函数返回一个 `std::unique_ptr`,可以使用这个指针来进行双工流的读写操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值