【gRPC-gateway】option定义规则及HttpBody响应

HTTP Option 定义规则

在 .proto 文件中,通过 google.api.http 注解定义 HTTP 路由规则,控制请求参数映射

需要在.proto文件显式

import https://github.com/googleapis/googleapis/tree/master/google/api


一、HTTP Option 定义规则详解

1. 基础路由定义
核心属性说明
属性作用底层原理
HTTP 方法
(get/post/put/patch/delete)
定义 RESTful 接口的 HTTP 动作映射到 http.RequestMethod 字段,路由匹配时校验方法一致性
body指定 HTTP 请求体的映射规则决定将请求体中的 JSON 数据解析到 Protobuf 消息的哪个字段
response_body控制 HTTP 响应体的数据来源(默认返回完整消息,可指定子字段)序列化响应时仅提取指定字段,其他字段将被忽略

关键场景示例
场景 1:简单 GET 请求
rpc GetUser(GetUserRequest) returns (User) {
option (google.api.http) = {
get: "/v1/users/{user_id}"  // 路径参数 user_id 映射到 GetUserRequest.user_id
};
}message GetUserRequest {
string user_id = 1;  // 必须与路径参数名称一致
}

请求映射逻辑

HTTP GET /v1/users/123 → GetUserRequest{user_id: "123"}

场景 2:POST 请求体映射
rpc CreateUser(CreateUserRequest) returns (User) {
option (google.api.http) = {
post: "/v1/users"
body: "user"  // 请求体映射到 CreateUserRequest.user 字段
};
}message CreateUserRequest {
User user = 1;  // 接收请求体数据
}

请求示例

POST /v1/users
{
"name": "Alice",
"email": "alice@example.com"
}

映射结果

CreateUserRequest{
user: User{name: "Alice", email: "alice@example.com"}
}

场景 3:混合参数绑定
rpc UpdateUser(UpdateUserRequest) returns (User) {
option (google.api.http) = {
patch: "/v1/users/{id}"
body: "*"  // 整个请求体映射到 UpdateUserRequest
};
}message UpdateUserRequest {
string id = 1;    // 来自路径参数
string name = 2;  // 来自请求体
int32 age = 3;    // 来自请求体
}

请求示例

PATCH /v1/users/456
{
"name": "Bob",
"age": 30
}

映射结果

UpdateUserRequest{
id: "456",
name: "Bob",
age: 30
}

2. body 属性的高级用法
规则对比表
语法行为适用场景
body: "*"整个请求体映射到 顶层消息对象简单请求,无额外路径/查询参数
body: "field"请求体映射到消息的 指定字段,其他字段从路径/查询参数获取混合参数请求(如更新操作)
body: ""禁用请求体映射,所有字段必须来自路径或查询参数GET/DELETE 等无 Body 请求

代码示例:body: "field" 的嵌套结构
rpc CreatePost(CreatePostRequest) returns (Post) {
option (google.api.http) = {
post: "/v1/posts"
body: "post_data"  // 请求体映射到 post_data 字段
};
}message CreatePostRequest {
string author_id = 1;        // 必须通过查询参数传递 ?author_id=xxx
PostData post_data = 2;      // 来自请求体
}message PostData {
string title = 1;
string content = 2;
}

请求示例

POST /v1/posts?author_id=789
{
"title": "Hello gRPC",
"content": "This is a tutorial..."
}

映射结果

CreatePostRequest{
author_id: "789",
post_data: PostData{
title: "Hello gRPC",
content: "This is a tutorial..."
}
}

3. response_body 的深度应用
默认行为 vs 指定字段
  • 未设置 response_body
rpc GetBook(GetBookRequest) returns (BookResponse) {
option (google.api.http) = {
get: "/v1/books/{id}"
};
}message BookResponse {
Book book = 1;
Metadata meta = 2;
}

响应结果

{
"book": {...},
"meta": {...}
}
  • 设置 response_body: "book"
rpc GetBook(GetBookRequest) returns (BookResponse) {
option (google.api.http) = {
get: "/v1/books/{id}"
response_body: "book"  // 仅返回 book 字段
};
}

响应结果

{
"title": "gRPC Guide",
"author": "..."
}

典型应用场景
  1. 精简响应数据
    隐藏内部元数据字段(如分页信息、服务状态码)

  2. 直接返回子对象
    当响应消息包含包装层时,直接暴露核心数据

  3. 兼容旧版 API
    维持响应结构不变的情况下修改 Protobuf 定义


4. 特殊语法与边界条件
路径参数冲突处理
// ❌ 错误示例:路径参数与 body 字段同名
rpc ConflictExample(ConflictRequest) returns (Empty) {
option (google.api.http) = {
post: "/v1/test/{id}"
body: "*"
};
}message ConflictRequest {
string id = 1;  // 同时来自路径参数和请求体,导致解析冲突
}

解决方案

  • 修改字段名称
  • 使用 body: "other_field" 避免覆盖

HttpBody 响应

HttpBody 是 gRPC-Gateway 中用于处理 非结构化响应数据 的核心机制。它允许直接返回二进制数据(如文件、图像、视频等),突破默认的 JSON 格式限制。


一、核心特性与使用场景
特性说明典型场景
原始二进制支持直接返回未经 JSON 序列化的数据文件下载(PDF、图片、音视频)
自定义 Content-Type可指定任意 MIME 类型(如 image/png返回特定格式数据(XML、CSV)
流式传输兼容可与 gRPC 流式结合使用(需自定义实现)大文件分块传输
低延迟处理避免 JSON 序列化/反序列化开销高性能二进制协议交互

二、Protobuf 定义详解
1. 基本定义格式
import "google/api/httpbody.proto";  // 必须导入service FileService {// 返回 HttpBody 类型rpc DownloadFile(FileRequest) returns (google.api.HttpBody) {option (google.api.http) = {get: "/v1/files/{name}"};}
}
2. 关键字段说明

HttpBody 的 Protobuf 定义如下:

message HttpBody {string content_type = 1;  // 必须指定 MIME 类型bytes data = 2;           // 原始二进制数据map<string, string> extensions = 3;  // 扩展元数据(较少使用)
}

三、服务端实现(Go 示例)
1. 返回静态文件
func (s *FileServer) DownloadFile(ctx context.Context, req *pb.FileRequest) (*httpbody.HttpBody, error) {// 读取文件内容data, err := os.ReadFile("/path/to/files/" + req.Name)if err != nil {return nil, status.Error(codes.NotFound, "file not found")}// 构造 HttpBody 响应return &httpbody.HttpBody{ContentType: "application/pdf",  // 根据实际文件类型修改Data:        data,}, nil
}
2. 动态生成二进制数据
func (s *ChartService) GenerateChart(ctx context.Context, req *pb.ChartRequest) (*httpbody.HttpBody, error) {// 生成图表(示例使用伪代码)img := generatePNGChart(req.Data)return &httpbody.HttpBody{ContentType: "image/png",Data:        img.Bytes(),}, nil
}

四、客户端请求示例
1. 直接通过浏览器下载
# 访问 URL 触发文件下载
http://localhost:8080/v1/files/report.pdf
2. 使用 curl 获取二进制数据
curl -v http://localhost:8080/v1/files/image.jpg --output result.jpg
3. 前端 JavaScript 处理
fetch('/v1/files/image.jpg').then(response => response.blob()).then(blob => {const url = window.URL.createObjectURL(blob);const a = document.createElement('a');a.href = url;a.download = 'image.jpg';a.click();});

五、高级配置与技巧
1. 自定义 Content-Type 规则
// 根据文件扩展名动态设置 Content-Type
func getContentType(filename string) string {switch path.Ext(filename) {case ".pdf": return "application/pdf"case ".png": return "image/png"case ".csv": return "text/csv"default: return "application/octet-stream"}
}
2. 流式传输大文件

虽然 HttpBody 本身不支持流式,但可通过以下方式实现分块传输:

func (s *FileServer) StreamFile(req *pb.FileRequest, stream pb.FileService_StreamFileServer) error {file, _ := os.Open(req.Name)defer file.Close()buffer := make([]byte, 1024*1024) // 1MB 分块for {n, err := file.Read(buffer)if err == io.EOF {break}stream.Send(&httpbody.HttpBody{ContentType: "application/octet-stream",Data:        buffer[:n],})}return nil
}

六、注意事项与调试指南
1. 常见问题排查表
问题现象可能原因解决方案
返回数据被 JSON 编码未正确设置为 HttpBody 返回类型检查 .proto 文件导入和类型定义
Content-Type 未生效服务端未设置 content_type 字段确保在 HttpBody 中显式指定类型
中文文件名乱码未设置 Content-Disposition 头通过 Metadata 添加额外响应头
2. 添加响应头示例
// 在拦截器中设置响应头
func setDownloadHeader(ctx context.Context, w http.ResponseWriter, resp proto.Message) {if body, ok := resp.(*httpbody.HttpBody); ok {filename := "export.csv"w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename))}
}// 注册到 ServeMux
mux := runtime.NewServeMux(runtime.WithForwardResponseOption(setDownloadHeader),
)

七、性能优化建议
  1. 启用 Gzip 压缩
    在网关层配置压缩中间件:

    handler := gziphandler.GzipHandler(mux)
    http.ListenAndServe(":8080", handler)
    
  2. 内存优化
    避免一次性加载大文件到内存,使用 io.Reader 流式处理:

    func streamFile(path string) (io.Reader, error) {return os.Open(path)
    }
    
  3. CDN 集成
    对于静态文件,直接返回重定向 URL:

    return &httpbody.HttpBody{ContentType: "text/plain",Data:        []byte("https://cdn.example.com/files/report.pdf"),
    }, nil
    

八、与普通响应的对比
特性普通响应(JSON)HttpBody 响应
数据格式强制 JSON 序列化保持原始二进制格式
Content-Typeapplication/json(固定)可自由定义(如 image/jpeg
元数据支持通过响应消息字段携带需通过 HTTP 头或自定义协议封装
性能开销有序列化/反序列化成本零转换开销(适合大文件)

https://github.com/0voice

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/10561.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux运维之Linux的安装和配置

目录 Linux的基本概念&#xff1a; 1.为什么要使用Linux&#xff1f; 2.什么是Linux&#xff1f; Linux的安装和配置&#xff1a; 1.下载Linux的虚拟机和镜像文件&#xff1a; 1.1下载虚拟机 1.2下载镜像文件 2.在虚拟机或者物理机中安装Linux操作系统 3.配置虚拟机的…

第一个3D程序!

运行效果 CPP #include <iostream> #include <fstream> #include <string> #include <cmath>#include <GL/glew.h> #include <GLFW/glfw3.h> #include <glm/glm.hpp> #include <glm/gtc/type_ptr.hpp> #include <glm/gtc/…

deepseek+vscode自动化测试脚本生成

近几日Deepseek大火,我这里也尝试了一下,确实很强。而目前vscode的AI toolkit插件也已经集成了deepseek R1,这里就介绍下在vscode中利用deepseek帮助我们完成自动化测试脚本的实践分享 安装AI ToolKit并启用Deepseek 微软官方提供了一个针对AI辅助的插件,也就是 AI Toolk…

简要介绍C++中的 max 和 min 函数以及返回值

简要介绍C中的 max 和 min 函数 在C中&#xff0c;std::max 和 std::min 是标准库 <algorithm> 中提供的函数&#xff0c;用于比较两个或多个值并返回最大值或最小值。这些函数非常强大且灵活&#xff0c;支持多种数据类型&#xff08;如整数、浮点数、字符串等&#xff…

【MyDB】4-VersionManager 之 3-死锁及超时检测

【MyDB】4-VersionManager 之 3-死锁及超时检测 死锁及超时检测案例背景LockTable锁请求与等待管理 addvm调用addputIntoList&#xff0c;isInList&#xff0c;removeFromList 死锁检测 hasDeadLock方法资源释放与重分配 参考资料 死锁及超时检测 本章涉及代码&#xff1a;top/…

Elasticsearch:如何搜索含有复合词的语言

作者&#xff1a;来自 Elastic Peter Straer 复合词在文本分析和标记过程中给搜索引擎带来挑战&#xff0c;因为它们会掩盖词语成分之间的有意义的联系。连字分解器标记过滤器等工具可以通过解构复合词来帮助解决这些问题。 德语以其长复合词而闻名&#xff1a;Rindfleischetik…

服务器虚拟化实战:架构、技术与最佳实践

&#x1f4dd;个人主页&#x1f339;&#xff1a;一ge科研小菜鸡-CSDN博客 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; 1. 引言 服务器虚拟化是现代 IT 基础设施的重要组成部分&#xff0c;通过虚拟化技术可以提高服务器资源利用率、降低硬件成本&am…

【LLM】Ollama框架入门指北

note Ollama是一个开源框架&#xff0c;专门设计用于在本地运行大型语言模型。它的主要特点是将模型权重、配置和数据捆绑到一个包中&#xff0c;从而优化了设置和配置细节&#xff0c;包括GPU使用情况&#xff0c;简化了在本地运行大型模型的过程。Ollama提供了对模型量化的支…

Linux系统:Ubuntu替换镜像源具体方法;

在Linux系统更新下载软件时&#xff0c;如遇因镜像源问题下载失败时&#xff0c;我们就需要替换系统原有镜像源&#xff0c;那么&#xff0c;此时&#xff0c;你是否还在百度四处搜索可以用的镜像源地址&#xff0c;然后反复去测试源地址的正确性呢&#xff0c;下面介绍一个亲测…

使用vhd虚拟磁盘安装两个win10系统

使用vhd虚拟磁盘安装两个win10系统 前言vhd虚拟磁盘技术简介准备工具开始动手实践1.winX选择磁盘管理2.选择“操作”--“创建VHD”3.自定义一个位置&#xff0c;输入虚拟磁盘大小4.右键初始化磁盘5.选择GPT分区表格式6.右键新建简单卷7.给卷起个名字&#xff0c;用于区分8.打开…

HTML(快速入门)

欢迎大家来到我的博客~欢迎大家对我的博客提出指导&#xff0c;有错误的地方会改进的哦~点击这里了解更多内容 目录 一、前言二、HTML基础2.1 什么是HTML?2.2 认识HTML标签2.2.1 HTML标签当中的基本结构2.2.2 标签层次结构 2.3 HTML常见标签2.3.1 标题标签2.3.2 段落标签2.3.3…

d3.js: Relation Graph

d3.js Tags d3/d3 GitHub D3 by Observable | The JavaScript library for bespoke data visualization 下载或 <!-- 引入 D3.js 库 --> <script src"https://d3js.org/d3.v7.min.js"></script> <!-- 引入 D3.js 库 --> <…

Oracle Primavera P6自动进行进度计算

前言 在P6 Professional 有一个自动计划计算的选项&#xff0c;很多人不了解该设置如何使用&#xff0c;以及什么时候该启动这项配置。 详情 P6 Professional 默认为非自动进度计算。启用自动选项后&#xff0c;可以快速查看调度更改的效果。 ​ ​ 如图所示&#xff0c;当你…

反射、枚举以及lambda表达式

一.反射 1.概念&#xff1a;Java的反射&#xff08;reflection&#xff09;机制是在运行状态中&#xff0c;对于任意一个类&#xff0c;都能够知道这个类的所有属性和方法&#xff1b;对于任意一个对象&#xff0c;都能够调用它的任意方法和属性&#xff0c;既然能拿到那么&am…

【Proteus仿真】【51单片机】简易计算器系统设计

目录 一、主要功能 二、使用步骤 三、硬件资源 四、软件设计 五、实验现象 联系作者 一、主要功能 1、LCD1602液晶显示 2、矩阵按键​ 3、可以进行简单的加减乘除运算 4、最大 9999*9999 二、使用步骤 系统运行后&#xff0c;LCD1602显示数据&#xff0c;通过矩阵按键…

HarmonyOS简介:HarmonyOS核心技术理念

核心理念 一次开发、多端部署可分可合、自由流转统一生态、原生智能 一次开发、多端部署 可分可合 自由流转 自由流转可分为跨端迁移和多端协同两种情况 统一生态 支持业界主流跨平台开发框架&#xff0c;通过多层次的开放能力提供统一接入标准&#xff0c;实现三方框架快速…

(即插即用模块-特征处理部分) 十九、(NeurIPS 2023) Prompt Block 提示生成 / 交互模块

文章目录 1、Prompt Block2、代码实现 paper&#xff1a;PromptIR: Prompting for All-in-One Blind Image Restoration Code&#xff1a;https://github.com/va1shn9v/PromptIR 1、Prompt Block 在解决现有图像恢复模型时&#xff0c;现有研究存在一些局限性&#xff1a; 现有…

Day24-【13003】短文,数据结构与算法开篇,什么是数据元素?数据结构有哪些类型?什么是抽象类型?

文章目录 13003数据结构与算法全书框架考试题型的分值分布如何&#xff1f; 本次内容概述绪论第一节概览什么是数据、数据元素&#xff0c;数据项&#xff0c;数据项的值&#xff1f;什么是数据结构&#xff1f;分哪两种集合形式&#xff08;逻辑和存储&#xff09;&#xff1f…

使用 MSYS2 qemu 尝鲜Arm64架构国产Linux系统

近期&#xff0c;我的师弟咨询我关于Arm64架构的国产CPU国产OS开发工具链问题。他们公司因为接手了一个国企的单子&#xff0c;需要在这类环境下开发程序。说实在的我也没有用过这个平台&#xff0c;但是基于常识&#xff0c;推测只要基于C和Qt&#xff0c;应该问题不大。 1. …

unity学习21:Application类与文件存储的位置

目录 1 unity是一个跨平台的引擎 1.1 使用 Application类&#xff0c;去读写文件 1.2 路径特点 1.2.1 相对位置/相对路径&#xff1a; 1.2.2 固定位置/绝对路径&#xff1a; 1.3 测试方法&#xff0c;仍然挂一个C#脚本在gb上 2 游戏数据文件夹路径&#xff08;只读&…