惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Engineering at Meta
Engineering at Meta
酷 壳 – CoolShell
酷 壳 – CoolShell
Forbes - Security
Forbes - Security
S
Schneier on Security
Cyberwarzone
Cyberwarzone
L
Lohrmann on Cybersecurity
NISL@THU
NISL@THU
T
Tenable Blog
Simon Willison's Weblog
Simon Willison's Weblog
G
GRAHAM CLULEY
Schneier on Security
Schneier on Security
K
Kaspersky official blog
AI
AI
Help Net Security
Help Net Security
Hacker News: Ask HN
Hacker News: Ask HN
Security Archives - TechRepublic
Security Archives - TechRepublic
T
Threatpost
Attack and Defense Labs
Attack and Defense Labs
I
Intezer
The Cloudflare Blog
博客园 - 叶小钗
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Blog — PlanetScale
Blog — PlanetScale
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
IT之家
IT之家
Recent Announcements
Recent Announcements
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
aimingoo的专栏
aimingoo的专栏
The GitHub Blog
The GitHub Blog
宝玉的分享
宝玉的分享
T
The Blog of Author Tim Ferriss
Y
Y Combinator Blog
O
OpenAI News
大猫的无限游戏
大猫的无限游戏
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
量子位
Microsoft Security Blog
Microsoft Security Blog
B
Blog
Jina AI
Jina AI
Hugging Face - Blog
Hugging Face - Blog
D
Docker
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
美团技术团队
Microsoft Azure Blog
Microsoft Azure Blog
H
Help Net Security
阮一峰的网络日志
阮一峰的网络日志
雷峰网
雷峰网
H
Hackread – Cybersecurity News, Data Breaches, AI and More
G
Google Developers Blog

kmcd.dev

Making Dynamic Protobuf Fast in Go Proxy, Record, and Mock gRPC APIs with FauxRPC Exploring Protocol Buffers Interactively Introducing ProtoDocs Ghost in the Shell: The Manga Behind the Anime The Hidden Cost of google.protobuf.Value Why Networking Built Its Own Data Modeling Language Zero-Friction Demos with WASM Let's Learn About BGP ConnectRPC: Where is it now? Building APIs with Contracts The Case for Greppable Code Unknown Fields in Protobuf IRC Log: Reactionary Faking protobuf data in Go Y'all are Sleeping on Mise-en-Place IRC Log: Standup 2 HTTP/2 From Scratch: Part 4 IRC Log: rm -rf /var/opt/gitlab/postgresql/data HTTP/2 From Scratch: Part 3 Building a Live BGP Map HTTP/2 From Scratch: Part 2 IRC Log: The Cloud Scale Incident Visualizing the Internet (2026) Shell Log: Namaste HTTP/2 From Scratch: Part 1 IRC Log: Standup HTTP/1.1 From Scratch WHOIS is dead, long live RDAP Months Considered Harmful Encryption vs. Compression On Creating My Own Cover Art Traceroute Tool from Scratch in Go My Favorite Interview Question From JSON to Protobuf Breaking gRPC Morse Code Can You Hack a Phone with Your Voice? Visualizing the Internet (2025) HTTP QUERY and Go I made a daily word game Protovalidate: Can Input Validation Be This Easy? Behold! The Barcode Scanner Mixing CEL and Protobuf for Fun FauxRPC and Protovalidate The Call of the Monolithic Codebase FauxRPC + Test Containers Self-Documenting Connect Services gRPC Over HTTP/3: Followup JSON to Protobuf Conversion gRPC: The Ugly Parts Working with Protobuf in 2024 Introducing FauxRPC HTTP/1.0 From Scratch Y'all are sleeping on HTTP/3 HTTP/0.9 From Scratch What version of HTTP are you using? Texans in Denmark gRPC Over HTTP/3 gRPC: The Good Parts Leaving Texas for Greener Pastures gRPC: The Bad Parts Unit Testing ConnectRPC Servers Daily Prompts Adding chart.js to Hugo Why I'm Rebranding Benchmarking gRPC (golang) Blog Update gRPC From Scratch: Part 3 - Protobuf Encoding Tracking the Wins Visualizing the Internet (2024) Dropping Unknown Fields in ConnectRPC RESTless: Web APIs After REST Introducing unknownconnect-go Making gRPC more approachable with ConnectRPC Inspecting Protobuf Messages Introducing protoc-gen-connect-openapi gRPC From Scratch: Part 2 - Server gRPC From Scratch: Part 1 - Client Why you should use gNMI over SNMP in 2026 The Rollercoaster of Productivity in Side Projects Lessons from a Decades-Long Project How I learned to code Economists with (virtual) Guns Visualizing the Internet (2023) softlayer-python: language bindings/CLI for a cloud company SwFTP: SFTP/FTP Server For Openstack Swift Video: Morning Copenhagen Commute Goodbye Evepraisal Visualizing the spectrum of the sun (Part 2) Visualizing the Internet (2022) Evepraisal: A price estimation tool for Eve Online Visualizing the spectrum of the sun
gRPC-Web Should Have Fixed gRPC
2026-07-14 · via kmcd.dev

gRPC did a lot right. It turned Protocol Buffers into an API design tool, delivering typed messages, generated clients, and strict contracts. For backend networks where you control every hop, it is a fantastic tool.

But gRPC tied itself too tightly to its HTTP/2 transport model. Specifically, it built core application behavior, like delivering final application status codes via response trailers, around protocol features that browser JavaScript could not fully expose.

Browsers support HTTP/2 at the network layer, but frontend JavaScript gets a much narrower API. Standard browser tools like fetch and XHR do not expose HTTP trailers to application code in the way native gRPC depends on. This left gRPC in an awkward position: the browser was using HTTP/2 underneath, but JavaScript could not make a native gRPC call.

The Compromise: gRPC-Web

gRPC-Web was the official answer to this problem. It adjusted the wire format by encoding trailer-like data directly into the response body, allowing browser clients to function.

It worked, but the deployment story usually required a proxy, which added friction and complexity. Because ordinary gRPC servers did not speak this variant natively, you usually had to run Envoy or another gRPC-Web translation layer just to bridge browser requests into your backend.

We accepted a specialized protocol for backend-to-backend efficiency, but bringing gRPC to the web involved extra parts. gRPC-Web was treated as a weird browser variant on the side instead of a mandate to simplify gRPC itself.

Unary Calls Should Be Boring

The real mistake was letting the hardest engineering cases define the common case. Most RPCs are not bidirectional streams. They are ordinary request-response operations: create a thing, fetch a thing, update a thing.

For these unary calls, the protocol should have used standard HTTP semantics.

That means using HTTP’s existing machinery instead of recreating it inside a custom message envelope. Content-Type should say whether the body is JSON or binary protobuf. For successful unary calls, the response can use the same format as the request. Developers should be able to use application/json in browsers or local curl calls for easy debugging, while production workloads can use a binary protobuf content type for better performance. Accept-Encoding should advertise supported compression formats, and Content-Encoding should describe the compression actually used. When the body size is known, Content-Length can say how large it is. When it is not known ahead of time, the underlying HTTP version already has ways to determine where the body ends.

For unary RPCs, gRPC’s extra length prefix and compression flag were not elegant protocol design. They were streaming machinery leaking into the boring case.

You should still define your schema in protobuf, generate your clients, and get type safety. But the network layer should look like this:

curl \
  -H 'Content-Type: application/json' \
  -d '{"userId":"123"}' \
  https://api.example.com/UserService/GetUser

If the operation naturally maps to an HTTP status, use it. If a user exists, return 200. If they do not, return 404. If the server crashes, return 500.

The standard counterargument from RPC purists is that HTTP status codes are too coarse. A 404 could mean the URL path is missing, or it could mean the requested database resource is missing. To avoid that ambiguity, gRPC often returns 200 OK for a successfully handled HTTP request and puts the RPC status in trailers.

But treating transport errors and application errors as completely separate worlds asks too much of the web. Load balancers, API gateways, CDNs, browser tools, and monitoring dashboards already understand 4xx and 5xx rates. Hiding application failures behind 200 OK makes that infrastructure less useful unless every layer becomes protocol-aware.

A web-native design should use standard HTTP status codes for coarse outcomes, then put richer domain-specific error details inside the JSON or binary response body.

Boring HTTP works. Browser dev tools understand it, standard middleboxes log it correctly, and tired engineers can debug it at 2 AM without specialized tools.

A practical protocol split would have been straightforward:

  • Unary calls: Standard HTTP request-response semantics.
  • Streaming calls: Framed messages over a stream-friendly transport.

The Web-Native Evolution

What I want from “the next version of gRPC” is not exotic. In fact, it already exists; it is exactly how ConnectRPC works. Connect preserves the protobuf service model and client generation, but treats unary calls as standard HTTP requests without the complexities of binary framing on top of HTTP. It proves that you can have type-safe contracts without forcing simple calls to cosplay as complex streams.

gRPC-Web should have been the moment gRPC admitted that the web was not a weird edge case. It should have been gRPC v2: protobuf contracts and generated clients on top of boring, inspectable, web-native HTTP, with special framing saved for real streaming instead of forced onto every unary call.

Instead, it became another compatibility layer. Useful, yes. But far less ambitious than it should have been.