从 gRPC 客户端调用
使用该服务。
从 gRPC 客户端调用 是 CoddyKit 上的免费 Learn Rust Coding 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Learn Rust Coding 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Learn Rust Coding 课程共包含 4 节课。
生成的客户端
tonic 会为每个服务生成一个客户端结构体,例如 GreeterClient,并将其放在 greeter_client 模块中。它为每个 rpc 提供一个异步方法。
您可以通过传输通道构造它,也可以直接连接到端点。
use greeter::v1::greeter_client::GreeterClient;
use greeter::v1::HelloRequest;连接到服务器
最简单的方式是使用 GreeterClient::connect,它接收地址字符串并返回已连接的客户端。
它必须在异步上下文中运行,因此请在 #[tokio::main] 下使用 .await 调用它。
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = GreeterClient::connect("http://[::1]:50051").await?;
Ok(())
}发起一元调用
将消息包装在 tonic::Request 中(或使用 Request::new),然后调用生成的方法。
响应是一个 tonic::Response;调用 .into_inner() 读取其中的消息。
let request = tonic::Request::new(HelloRequest { name: "Ada".into() });
let response = client.say_hello(request).await?;
println!("{}", response.into_inner().message);处理 Status 错误
如果服务器返回错误,此调用会得到 Err(Status)。检查 status.code() 和 status.message(),并据此进行处理。
这与服务器端的行为相对应:NotFound 或 Unauthenticated 等状态码会传回客户端。
match client.say_hello(req).await {
Ok(resp) => println!("{}", resp.into_inner().message),
Err(status) => eprintln!("{}: {}", status.code(), status.message()),
}构建通道
如需复用和配置,请使用 Endpoint 显式构建 Channel。您可以设置超时、TCP 保活和连接选项。
然后使用 GreeterClient::new(channel) 构造客户端。
use tonic::transport::{Channel, Endpoint};
let channel = Endpoint::from_static("http://[::1]:50051")
.timeout(std::time::Duration::from_secs(5))
.connect()
.await?;
let mut client = GreeterClient::new(channel);发送元数据
发送请求前,将身份验证令牌等标头插入请求元数据,即可附加这些标头。
请使用 MetadataValue 表示值;它必须是有效的 ASCII 标头值。
use tonic::metadata::MetadataValue;
let mut req = tonic::Request::new(HelloRequest { name: "Ada".into() });
let token: MetadataValue<_> = "Bearer abc123".parse()?;
req.metadata_mut().insert("authorization", token);单次调用截止时间
设置截止时间,避免服务器响应缓慢导致客户端一直等待。如果超时,请求上的 set_timeout 会以 DeadlineExceeded 状态中止请求。
截止时间会传递到服务器,服务器可以提前停止工作。
let mut req = tonic::Request::new(HelloRequest { name: "Ada".into() });
req.set_timeout(std::time::Duration::from_secs(2));
let resp = client.say_hello(req).await?;接收服务器流
服务器流式调用会返回一个流。使用 into_inner() 获取它,然后在循环中通过 message().await 拉取消息,直到得到 None。
每次迭代都会得到一条解码后的响应。
let mut stream = client.server_stream(req).await?.into_inner();
while let Some(item) = stream.message().await? {
println!("{:?}", item);
}客户端流式传输
对于客户端流式调用,请传入请求的异步流。使用 tokio_stream 包装迭代器或通道,然后将其交给该方法。
完成发送后,服务器才会返回唯一的响应。
use tokio_stream::iter;
let outbound = iter(vec![msg1, msg2, msg3]);
let response = client.client_stream(Request::new(outbound)).await?;
println!("{:?}", response.into_inner());TLS 连接
如需加密传输,请使用 CA 证书和服务器域名配置 ClientTlsConfig,然后通过 https 连接。
这要求 tonic 依赖启用 tls 功能。
use tonic::transport::{ClientTlsConfig, Endpoint};
let tls = ClientTlsConfig::new().domain_name("example.com");
let channel = Endpoint::from_static("https://example.com:50051")
.tls_config(tls)?
.connect()
.await?;复用客户端
底层 Channel 易于克隆,并会通过一个 HTTP/2 连接复用请求。请在多个任务之间克隆客户端,而不要反复重新连接。
这样可以在并发场景下降低连接建立成本。
let client = GreeterClient::new(channel);
let mut c1 = client.clone();
let mut c2 = client.clone();
// use c1 and c2 in separate tokio tasks快速检查
在 tonic 中,如何读取一元客户端调用的结果?
回顾
您连接了生成的客户端,发起了一元调用,处理了 Status 错误,构建了经过配置的通道,发送了元数据,设置了截止时间,接收了服务器流和客户端流,启用了 TLS,并复用了易于克隆的客户端。
现在,您已经可以端到端地构建完整的基于 tonic 的 gRPC 服务。
用 AI 导师学习 Rust — 免费
在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。
- 课程
- 39
- 课程
- 144
常见问题解答
「从 gRPC 客户端调用」课时是免费的吗?
是的 — 「从 gRPC 客户端调用」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Learn Rust Coding 课程的其余内容,请升级到 CoddyKit PRO。 Learn Rust Coding 课程共包含 4 节课。
「从 gRPC 客户端调用」这节课中我会学到什么?
使用该服务。 你通过在浏览器中直接运行的动手代码来练习 Learn Rust Coding,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Learn Rust Coding 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Learn Rust Coding 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「从 gRPC 客户端调用」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Learn Rust Coding 课中编写并运行代码吗?
能。每节 Learn Rust Coding 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- Protobuf 与服务定义
- 使用 tonic-build 生成代码
- 实现 gRPC 服务器
- 从 gRPC 客户端调用