You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决浏览器向gRPC服务器发送数据时的net::ERR_INVALID_HTTP_RESPONSE错误

问题原因及解决方案

问题描述

向http://localhost:50051/helloworld.Greeter/SayHello发送请求时,浏览器控制台报错:

POST http://localhost:50051/helloworld.Greeter/SayHello net::ERR_INVALID_HTTP_RESPONSE
....
(index):49 Error: TypeError: Failed to fetch

服务器无任何报错输出。

核心原因

当前搭建的是原生gRPC服务器,它基于HTTP/2的二进制协议通信;但浏览器端用fetch发送的是HTTP/1.1协议的请求,两者协议不兼容。gRPC服务器返回的响应不符合HTTP/1.1规范,导致浏览器判定为无效HTTP响应。

解决方案

浏览器原生不支持gRPC协议,推荐使用gRPC-Web实现浏览器与gRPC服务的通信,以下是具体实现步骤:

步骤1:调整服务端,添加gRPC-Web代理

安装所需依赖:

npm install @grpc/grpc-js @grpc/proto-loader grpc-web express

替换原server.mjs代码,同时启动gRPC原生服务和gRPC-Web代理:

import grpc from "@grpc/grpc-js";
import protoLoader from "@grpc/proto-loader";
import path from "path";
import { fileURLToPath } from "url";
import express from "express";
import { grpcWebMiddleware } from "grpc-web";

const PROTO_PATH = path.join(process.cwd(), "./helloworld.proto");
const packageDefinition = protoLoader.loadSync(PROTO_PATH, {});
const helloProto = grpc.loadPackageDefinition(packageDefinition).helloworld;

// gRPC服务逻辑
function sayHello(call, callback) {
  callback(null, { message: "Hello " + call.request.name });
}

// 启动原生gRPC服务(端口50052)
const grpcServer = new grpc.Server();
grpcServer.addService(helloProto.Greeter.service, { sayHello });
grpcServer.bindAsync(
  "0.0.0.0:50052",
  grpc.ServerCredentials.createInsecure(),
  () => {
    grpcServer.start();
    console.log("原生gRPC服务运行于 http://0.0.0.0:50052");
  }
);

// 启动Express服务作为gRPC-Web代理(端口50051)
const app = express();
app.use(express.raw({ type: "application/x-protobuf" }));
app.use(grpcWebMiddleware({ backend: "grpc://localhost:50052" }));

app.listen(50051, () => {
  console.log("gRPC-Web代理运行于 http://0.0.0.0:50051");
});

步骤2:修改客户端,使用gRPC-Web SDK

替换原index.html代码,引入gRPC-Web库并创建客户端:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>gRPC Client</title>
  <script src="https://cdn.jsdelivr.net/npm/protobufjs/dist/protobuf.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/grpc-web@1.5.0/dist/grpc-web.min.js"></script>
</head>
<body>
  <script>
    const protoPath = "helloworld.proto";
    protobuf.load(protoPath, (err, root) => {
      if (err) throw err;

      // 创建gRPC-Web客户端
      const greeterService = root.lookupService("helloworld.Greeter");
      const client = new grpc.GrpcWebClientBase({ host: "http://localhost:50051" });

      // 构造并发送请求
      const request = root.lookupType("helloworld.HelloRequest").create({ name: "World" });
      const requestBuffer = root.lookupType("helloworld.HelloRequest").encode(request).finish();

      client.unary(
        greeterService.methods.sayHello,
        {
          request: requestBuffer,
          metadata: {}
        },
        (err, response) => {
          if (err) {
            console.error("请求失败:", err);
            return;
          }
          const reply = root.lookupType("helloworld.HelloReply").decode(response.message);
          console.log("响应结果:", reply.message);
        }
      );
    });
  </script>
</body>
</html>

步骤3:启动并验证

  1. 启动服务端:node server.mjs
  2. 启动客户端静态服务:npx http-server -o
  3. 打开浏览器控制台,即可看到响应结果: Hello World的输出。

内容的提问来源于stack exchange,提问作者Jon You

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 16:14:51