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

推荐订阅源

Engineering at Meta
Engineering at Meta
G
GRAHAM CLULEY
Attack and Defense Labs
Attack and Defense Labs
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Tor Project blog
T
Threat Research - Cisco Blogs
阮一峰的网络日志
阮一峰的网络日志
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Vercel News
Vercel News
Google DeepMind News
Google DeepMind News
U
Unit 42
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Spread Privacy
Spread Privacy
C
CXSECURITY Database RSS Feed - CXSecurity.com
量子位
T
The Blog of Author Tim Ferriss
Project Zero
Project Zero
Webroot Blog
Webroot Blog
雷峰网
雷峰网
C
Cyber Attacks, Cyber Crime and Cyber Security
Microsoft Azure Blog
Microsoft Azure Blog
Microsoft Security Blog
Microsoft Security Blog
Scott Helme
Scott Helme
T
The Exploit Database - CXSecurity.com
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
A
About on SuperTechFans
NISL@THU
NISL@THU
AWS News Blog
AWS News Blog
Security Latest
Security Latest
S
Schneier on Security
W
WeLiveSecurity
K
Kaspersky official blog
有赞技术团队
有赞技术团队
Cyberwarzone
Cyberwarzone
P
Palo Alto Networks Blog
TaoSecurity Blog
TaoSecurity Blog
G
Google Developers Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Schneier on Security
Schneier on Security
博客园_首页
博客园 - 司徒正美
Application and Cybersecurity Blog
Application and Cybersecurity Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
C
Check Point Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Recent Commits to openclaw:main
Recent Commits to openclaw:main
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Know Your Adversary
Know Your Adversary
P
Privacy & Cybersecurity Law Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"

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.