connectrpc / connect-es

The TypeScript implementation of Connect: Protobuf RPC that works.
https://connectrpc.com/
Apache License 2.0
1.39k stars 81 forks source link

@connectrpc/connect-web@2.0.0-beta.2 nextjs web send api error #1281

Closed li1234yun closed 1 month ago

li1234yun commented 1 month ago

Describe the bug When I use latest connectrpc beta2 package to send api request, I met this error:

{
    "message": "grpc: error unmarshalling request: proto:%C2%A0cannot parse invalid wire-format data",
    "code": "internal"
}

package.json dependencies:

  "dependencies": {
    "@bufbuild/protobuf": "^2.2.0",
    "@connectrpc/connect": "2.0.0-beta.2",
    "@connectrpc/connect-node": "2.0.0-beta.2",
    "@connectrpc/connect-web": "2.0.0-beta.2",
  }

As clearly as you can, please tell us what the bug is.

To Reproduce

// code snippet

// axios.ts
const interceptor: Interceptor = (next) => async (req) => {
  req.header.set('X-Session', session.id)

  const token = session.token()
  if (token) {
    req.header.set('Authorization', token)
  }

  // try {
  //   const res = await next(req)
  //   return res
  // } catch (e) {
  //   console.error('request error: ', e)
  //   throw e
  // }

  return await next(req)
}

const transport = createConnectTransport({
  baseUrl: 'http://127.0.0.1:10000'
  useBinaryFormat: false,
  interceptors: [interceptor],
  useHttpGet: false,
  fetch: globalThis.fetch,
})

const clients = {
  authAccountClient: createClient(
    entry.auth.account.AuthAccountService,
    transport
  )
}

// page.tsx
clients.authAuthenticationClient
  .getOauth2ProviderAuthorizeUrl({
    type: services.auth.authentication.Oauth2ProviderEnum_Oauth2Provider
      .GOOGLE,
  })
  .then((res) => {
    console.log('res:', res)
    router.push(res.url)
  })

Environment (please complete the following information):

If your problem is specific to bundling, please also provide the following information:

// package.json
"devDependencies": {
  "@babel/core": "^7.20.2",
  "@rollup/plugin-babel": "^6.0.3",
  "@rollup/plugin-commonjs": "^28.0.0",
  "@rollup/plugin-node-resolve": "^15.0.1",
  "@rollup/plugin-typescript": "^12.1.0",
  "rollup": "^4.24.0",
  "tslib": "^2.4.1",
  "typescript": "^5.6.3"
}

// bundle config
import babel from "@rollup/plugin-babel";
import commonjs from "@rollup/plugin-commonjs";
import resolve from "@rollup/plugin-node-resolve";
import typescript from "@rollup/plugin-typescript";

export default [
  {
    input: "src/index.ts",
    output: {
      dir: "dist",
      format: "es",
      sourcemap: true,
    },
    plugins: [
      typescript(),
      resolve(),
      commonjs(),
      babel({
        exclude: "node_modules/**",
        babelHelpers: "bundled",
      }),
    ],
  },
];

Additional context

image image

timostamm commented 1 month ago

Thanks for sharing the details!

The Connect transport from @connectrpc/connect-web uses the Protobuf JSON format by default (because that's easy to debug in a web browser). buf curl will send the data in the Protobuf binary format.

It looks like your server tries to decode the JSON request as Protobuf binary, and fails. As a simple fix, you should be able to pass useBinaryFormat: true to the transport.

If you prefer to send JSON, you have to configure the server to accept it. Are you using grpc-go behind Envoy with the Connect bridge? It translates the Protocol, but it cannot translate the Payload between binary and JSON. But you can configure grpc-go to support JSON, see the example here.

li1234yun commented 1 month ago

If you prefer to send JSON, you have to configure the server to accept it. Are you using grpc-go behind Envoy with the Connect bridge?

Yes, I use envoy proxy from connectrpc example. The envoy proxies grpc-go backend services as you said, I will try later.

Thank you very much! @timostamm

li1234yun commented 1 month ago

@timostamm I try as you said.

{
    "message": "grpc: error unmarshalling request: proto:%C2%A0cannot parse invalid wire-format data",
    "code": "internal"
}
timostamm commented 1 month ago

Thanks for confirming. Looks like it's working as expected, then.

For grpc-go, don't forget the blank import to register the codec: https://github.com/connectrpc/envoy-demo/blob/93368e549b12099beb1ebfd4176bfb75c3f0fb0b/server.go#L29

If that doesn't change the result, please open an issue in the envoy-demo repository.

li1234yun commented 1 month ago

Thank you again @timostamm !

I found my problem, because my grpc-backend services proxied by dapr sidecar. Dapr sidecar grpc server doesn't achieve the json codec support.

If I call grpc-go with codec directly, the api call will be ok.