improbable-eng / grpc-web Goto Github PK
View Code? Open in Web Editor NEWgRPC Web implementation for Golang and TypeScript
License: Apache License 2.0
gRPC Web implementation for Golang and TypeScript
License: Apache License 2.0
I'm trying to use grpc-web with a python backend. I keep getting the following output from the grpc-web-client:
status 13 Response closed without headers
Perhaps someone can point me in the right direction
Debug output from the grpc-server:
localhost:4200..User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36..Access-Control-Request-Headers: content-type,x-grpc-web..Accept: */*..Referer: http://localhost:4200/login..Accept-Encoding: gzip, deflate, br..Accept-Language: en-US,en;q=0.8,en-GB;q=0.6,sv;q=0.4....' D1013 11:20:41.749662000 123145419489280 chttp2_transport.c:2546] set connectivity_state=4 D1013 11:20:41.749700000 123145419489280 connectivity_state.c:171] SET: 0x7fa8f5072850 server_transport: READY --> SHUTDOWN [close_transport] error=0x7fa8f4e89030 {"created":"@1507886441.749660000","description":"Failed parsing HTTP/2","file":"src/core/ext/transport/chttp2/transport/chttp2_transport.c","file_line":2342,"grpc_status":14,"referenced_errors":[{"created":"@1507886441.749656000","description":"Connect string mismatch: expected 'P' (80) got 'O' (79) at byte 0","file":"src/core/ext/transport/chttp2/transport/parsing.c","file_line":104}]}
//Jonas
Is there already support for this flag?
my grpc server is running on localhost with a self-signed certificate (issued for localhost) but giving the rootCA.pem to grpcwebproxy doesn't work:
./bin/grpcwebproxy --server_tls_cert_file=/home/me/crt/localhost.crt --server_tls_key_file=/home/me/crt/localhost.key --server_tls_client_ca_files=/home/me/crt/rootCA.pem --backend_addr=localhost:50052
complains:
Failed to dial localhost:50052: connection error: desc = "transport: x509: certificate signed by unknown authority"; please retry
Many thanks
Here's a fairly common thing I'm trying to do, but can't find docs to describe.
I'm running this gRPC app behind a load balancer, which sets an HTTP header of the remote IP address. How can I fetch that in the gRPC server for logging purposes? Will that still work with streaming?
I'm facing a scenario where I have to talk to a gRPC server that sits behind a reverse proxy which redirects to ADFS for login and sets a http-only session cookie which it will pick up on subsequent requests and attaches an Authorization
header. The problem is that the transports don't set the cookies with the gRPC invocation, so each POST results in a redirect.
What do you think about adding an option somewhere which could set the withCredentials
property of the XMLHttpRequest
before sending the request?
Is there a native browser javascript client library for making requests to your grpcweb server?
If not, how to understand how such a client should be implemented? In particular: the format of messages, the transport(s) to use. Code examples together with example network traces would be the best.
Thanks
Note: I'm aware of the spec https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-WEB.md
I've been playing around with gRPC-Web for my GopherJS bindings, and I noticed that if I remove the stream.SendHeader
call in QueryBooks
I get the following error:
Response closed without grpc-status (Headers only)
The onEnd
headers look like so:
access-control-allow-credentials:[true]
access-control-allow-origin:[https://localhost:10000]
content-type:[application/octet-stream]
date:[Fri, 23 Jun 2017 08:46:36 GMT]
status:[200]
strict-transport-security:[max-age=31536000; includeSubDomains; preload]
vary:[Origin]
Indeed, the grpc-status
header is missing. When the SendHeaders
call is added back the onEnd
headers look like so instead:
grpc-status:[0]
I've tried debugging this a little but It'd be cool to know if this is reproducible on your end of if it's a problem with my setup. The source repo I'm using is https://github.com/johanbrandhorst/grpcweb-example.
As described in README:
The gRPC semantics encourage you to make multiple requests at once.
What's the recommended approach to make multiple concurrent requests with grpc-web client?
For example, axios provide a way to deal with multipe concurrent requests like:
function getUserAccount() {
return axios.get('/user/12345');
}
function getUserPermissions() {
return axios.get('/user/12345/permissions');
}
axios.all([getUserAccount(), getUserPermissions()])
.then(axios.spread(function (acct, perms) {
// Both requests are now complete
}));
I checked gprc.d.ts and didn't find a clue to add a handler function for when all request are complete. So for make multiple requests at once in grpc-web client, does it mean to invoke grpc.invoke() inside of some other framework functions? Could you share your ideas for the best practise of making multiple requests at once in grpc-web client. Thank you very much.
Is it possible to write the server using grpc-java and call it from browser using grpc-web?
How to wire them together?
Love where this is going. Are you thinking jsonpb codec as an option or default for generated deserializer? IMHO this would be much better than protobufjs as browser decode speed is way better for json than the base64 hackery used in protobufjs.
Either way if it could support multiple codecs as per spec someone else can add.
I am wondering if this can be made to use with plain ES5 javascript without the typescript bits. I tried for a while to integrate it in a normal ReactJS workflow but I could not do it without TS
Hello,
my preflight request is OK, but then I'm POSTing my proto message buffer using fetch to the grpcwebproxy using:
fetch('https://localhost:8443/package.service/Method', {
method: 'POST',
headers: new Headers({
'Content-Type': 'application/grpc-web',
}),
body: GetInstrumentsRequest.encode(message).finish(),
})
And the grpcwebproxy throws:
ERRO[0121] finished streaming call error="rpc error: code = Internal desc = failed proxying s2c: rpc error: code = Internal desc = grpc: received message length 105465393 exceeding the max size 4194304" grpc.code=Internal grpc.method=GetInstruments grpc.service=package.service grpc.time_ns=352.723ยตs system=grpc
And my node-grpc logs:
D0411 17:19:02.735121065 20308 chttp2_transport.c:1212] perform_stream_op[s=0x7f8594013828/3]: [COVERED] SEND_INITIAL_METADATA{key=3a 73 74 61 74 75 73 ':status' value=32 30 30 '200', key=63 6f 6e 74 65 6e 74 2d 74 79 70 65 'content-type' value=61 70 70 6c 69 63 61 74 69 6f 6e 2f 67 72 70 63 'application/grpc', key=67 72 70 63 2d 65 6e 63 6f 64 69 6e 67 'grpc-encoding' value=69 64 65 6e 74 69 74 79 'identity', key=67 72 70 63 2d 61 63 63 65 70 74 2d 65 6e 63 6f 64 69 6e 67 'grpc-accept-encoding' value=69 64 65 6e 74 69 74 79 2c 64 65 66 6c 61 74 65 2c 67 7a 69 70 'identity,deflate,gzip'} SEND_TRAILING_METADATA{key=67 72 70 63 2d 73 74 61 74 75 73 'grpc-status' value=31 33 '13', key=67 72 70 63 2d 6d 65 73 73 61 67 65 'grpc-message' value=49 6c 6c 65 67 61 6c 20 62 75 66 66 65 72 'Illegal buffer'}
I0411 17:19:02.735298783 20334 chttp2_transport.c:983] HTTP:3:HDR:SVR: :status: 200
I0411 17:19:02.735306943 20334 chttp2_transport.c:983] HTTP:3:HDR:SVR: content-type: application/grpc
I0411 17:19:02.735314917 20334 chttp2_transport.c:983] HTTP:3:HDR:SVR: grpc-encoding: identity
I0411 17:19:02.735323738 20334 chttp2_transport.c:983] HTTP:3:TRL:SVR: grpc-status: 13
D0411 17:19:02.735351624 20334 chttp2_transport.c:863] complete_closure_step: 0x7f8594012680 refs=1 flags=0x0002 desc=send_initial_metadata_finished err={"created":"@1491902342.735336170","description":"Attempt to send initial metadata after stream was closed","file":"../src/core/ext/transport/chttp2/transport/chttp2_transport.c","file_line":1084}
Any idea where the problem could come from?
Many thanks
How would one go about including authentication tokens in the grpc-web-client
? I see the metadata
in the RpcOptions
type however when I try to use it TypeScript says that property isn't valid.
grpc.invoke(BookService.GetBooks, {
request: new BookFilter(),
host: 'http://localhost:9090',
onEnd: (code: grpc.Code, msg: string, trailers: BrowserHeaders) => {
console.log('getBooks.onEnd', code, msg, trailers);
},
});
This is an example of how I am trying to include/use it.
Does this handle streaming over websockets for doing push upwards from a golang server ?
I am using grpcwebproxy. My backend server is a node js grpc server. I want pass metadata through grpc-web-client.
const testRequest = new TestRequest();
testRequest.setUserId('testuserid');
grpc.unary(MeetService.testHistory, {
request: testRequest,
host: host,
debug: true,
metadata: {test_token: 'xxxxxxxxxxx'},
onEnd: res => {
const { status, statusMessage, headers, message, trailers } = res;
if (status === Code.OK && message) {
// console.log('meetHistory.onEnd.message', message.toObject());
}
// console.log('meetHistory.onEnd.trailers', trailers);
}
});
But my node server cannot get metadata. It only can get a user-agent metadata.
Metadata { _internal_repr: { 'user-agent': [ 'grpc-go/1.7.0-dev' ] } }
ServerUnaryCall {
domain: null,
_events: { error: [Function] },
_eventsCount: 1,
_maxListeners: undefined,
call: Call {},
cancelled: false,
metadata: Metadata { _internal_repr: { 'user-agent': [Array] } },
request:
{ wrappers_: null,
messageId_: undefined,
arrayIndexOffset_: -1,
array: [ 'testuserid' ],
pivot_: 1.7976931348623157e+308,
convertedFloatingPointFields_: {} } }
Hello guys,
is the proxy capable of serving a HTTP only endpoint (no TLS) and route that to a classic no-TLS Java gRPC server?
I'll be that guy ;-)
A code generator for Dart web clients would be really nice...
Hi. I try run example.
I do:
git clone https://github.com/improbable-eng/grpc-web
cd grpc-web/example/
# then I install go from brew and set:
# export GOPATH=$HOME/work
# export GOBIN=$HOME/work/bin
npm install
npm run get_go_deps
npm start
and I get the error:
[0] go/exampleserver/exampleserver.go:18:2: cannot find package "github.com/improbable-eng/grpc-web/go/grpcweb" in any of:
[0] /usr/local/Cellar/go/1.9.2/libexec/src/github.com/improbable-eng/grpc-web/go/grpcweb (from $GOROOT)
[0] /Users/ezheg/work/src/github.com/improbable-eng/grpc-web/go/grpcweb (from $GOPATH)
Thanks very much for this project. Just a thought - it would be nice to see the project designed in such a way that the transport can be swapped out. I think a WS/WSS transport would work quite well for gRPC-Web with full streaming support and even better browser compatibility than what this current project supports.
I understand that the browser is lacking a feature to fully support grpc protocol (that may arrive in 2 years). I deduce that my only way to request data from grpc server using a browser is to go through a gateway...
So the gateway needs to talk HTTP on one side, and GPRC on the other...correct?
So the MAJOR barrier to bring grpc to the web is to have a robust gateway (would it be written in go, or c++...), the browser library to send the requests would be as easy as using fetch in recent browsers...
If I'm correct on these points, I don't understand how the official grpc-web-gateway (not open-sourced yet) could be still not following the last grpc-web specs, and why this present grpcwebproxy seems to not be the "killer program" of this current repository?
I'm just trying to get some insights from the people who have a full picture of the whole situation, As I'm struggling to get a simple grpc unaryCall working over http....
Many thanks!
I have a working example of accessing a stream using grpc.invoke
however there seems to be no way to cancel. Would think there would be something like setInterval
ala...
const cancelId = grpc.invoke(...)
grpc.cancelnvoke(cancelId)
thoughts?
As per discussion in #88, onEnd()
callback on a grpc-web request should be called when a request is cancelled.
Requires:
onEnd()
when a request is abortedHello, I'm working with @pjm17971 and this is a follow up to #79. Thanks for grpc-web -- I think it's fantastic idea and we'd really love to use it in our project.
We're trying to use the grpc-web proxy to talk to an gRPC server that is fronted by Google Cloud Endpoints -- I've attached a diagram. We are using JWT tokens for authentication. It seems like the token isn't making it through the grpcwebproxy. I've looked at the code and I can't see why that isn't getting passed through.
Do you think the JWT token should be making it through to the backend server? Is there someplace I'd need to add something to help with that? I'm totally fine adding some code but I'm not sure I fully get how the proxy works and so I'm not sure if that would be an adjustment to the grpcwebproxy code or perhaps to the grpc-proxy library. Any pointer you could give would be greatly appreciated!
In my application, the client requests data that is returned through a stream. But if the client crashes, the server keeps writing into the stream without any error.
I need to authenticate user with Github. But I am having difficult time in understanding how to do it in grpc-web
. I google it for several times and asked in stackoverflow, but no luck. I will appreciate if anyone can give me an example or any sort of help.
Are their any plans to create one? It would be a useful medium to anything that doesn't fit into a github issue.
message validationReq {
string accessToken = 1;
}
Produces a typings file with definitions like setAccessToken(...).
However the produced javascript does not honor the camelcase and creates the prototype function setAccesstoken(...).
Is this a .proto convention? A bug? It's late so I'm filing a short bug to see if there is a simple answer. Please let me know if more information is needed and I'd be happy to oblige.
Hello,
I still didn't try the grpcwebproxy, but I'd like to make sure about this point:
Many thanks!
Headers and Trailers with multiple values for the same key are being handled differently. Headers are being concatenated into a single string, whereas Trailers retain the individual values.
Setting response headers with:
grpc.SendHeader(ctx, metadata.Pairs("HeaderTestKey1", "ServerValue1A", "HeaderTestKey1", "ServerValue1B", "HeaderTestKey2", "ServerValue2"))
and response trailers with:
grpc.SetTrailer(ctx, metadata.Pairs("TrailerTestKey1", "ServerValue1A", "TrailerTestKey1", "ServerValue1B", "TrailerTestKey2", "ServerValue2"))
Produces inconsistent handling in Chrome 57:
onHeaders: function(headers: BrowserHeaders) {
console.log("headers", JSON.stringify(headers));
// ...
// "headertestkey1": [
// "ServerValue1A, ServerValue1B"
// ],
// "headertestkey2": [
// "ServerValue2"
// ]
onEnd: function(code: grpc.Code, msg: string, trailers: BrowserHeaders) {
console.log("trailers", JSON.stringify(trailers));
// ...
// "trailertestkey1": [
// "ServerValue1A",
// "ServerValue1B"
// ],
// "trailertestkey2": [
// "ServerValue2"
// ]
Currently the error checking and mapping to gRPC codes is quite basic.
This needs revisiting to conform with https://github.com/grpc/grpc/blob/master/doc/statuscodes.md
Hi,
This library looks super useful, but a question:
I have a gRPC server running (node.js), deployed onto Google Cloud with GKE and Cloud Endpoints. Another node.js client is capable of calling this endpoint from inside or outside of GCP using an JWT token and that works fine. Is it possible to use this library with such a cloud endpoint and call my service from a web application?
Thanks!
I tried to clean up the project structure a little bit as a means of groking the project and found that changing the structure of the /proto directory caused a failing build due to an improper import statement in the generated typescript code.
Changing /proto/examplecom/library/book_service.proto
To /proto/book_service.proto
And changing the package name accordingly from examplecom.library to books in the proto file.
Caused the statement
import * as examplecom_library_book_service_pb from "../../examplecom/library/book_service_pb";
to be changed to
import * as book_service_pb from "book_service_pb";
which causes webpack to fail.
Manually changing the import to "./book_service_pb" caused the error to go away but I understand
you aren't supposed to manually change the generated code.
Thoughts? Let me know if you want me to give more examples.
Are there any handy debug tools which could be used to check data in req/res at browser side?
Chrome developer tools can't resolve gprc message, instead it always show "This request has no response data available".
And can't find any Chrome extension to resolve grpc message.
Is there any way to cancel server push from client after method was invoked?
E.g. i want to be able to cancel current request and invoke new one with different parameters (filters change on page). But i do not see how i can get to connection.
Currently the http://
tests (which test HTTP1.1) are flaky when run through BrowserStack on all browsers. The same tests locally work as expected. Hypothesis of the root cause is the BrowserStack tunnel that is used to proxy requests.
https://
tests (which test HTTP2) are unaffected
Is there any possibility to wrap the the gRPC proxy server without allowing CORS? We already have a gateway that serves all preflight requests, however, the headers are doubled as grpc web proxy also adds headers to the response.
nodeHttpRequest must subscribe and propagate "aborted"
Hi there,
If I run grpc-web on angular2 everything works well. If I am testing the gui with protractor/selenium and chrome everything works as intended too, but when adding the --headless
flag to chrome it reports an grpc error code 13 on every grpc.invoke
onEnd()
handler. Is it possible that it does not work in headless chrome somehow?
Thank you very much for your help!
Our website use the Universal Rendering, I succeeded to run the standalone grpcwebproxy with client side rendering, but when it comes to server side rendering, I got the error
ReferenceError: XMLHttpRequest is not defined
at getXHR (/**/node_modules/grpc-web-client/src/transports/Transport.ts:27:7)
at xhrSupportsResponseType (/**/node_modules/grpc-web-client/src/transports/Transport.ts:37:15)
at Function.DefaultTransportFactory.detectTransport (/**/node_modules/grpc-web-client/src/transports/Transport.ts:62:9)
at Function.DefaultTransportFactory.getTransport (/**/node_modules/grpc-web-client/src/transports/Transport.ts:52:47)
at Object.invoke (/**/node_modules/grpc-web-client/src/grpc.ts:160:43)
at /**/src/helpers/books.js:11:10
at F (/**/node_modules/core-js/library/modules/_export.js:35:28)
at batchGetBook (/**/src/helpers/books.js:10:10)
at /**/src/redux/modules/full.js:96:12
at Object.promise (/**/src/containers/Book/Book.js:17:19)
at /**/node_modules/redux-async-connect/lib/ReduxAsyncConnect.js:118:34
at Array.reduce (native)
at /**/node_modules/redux-async-connect/lib/ReduxAsyncConnect.js:117:35
at Array.map (native)
at loadAsyncConnect (/**/node_modules/redux-async-connect/lib/ReduxAsyncConnect.js:114:68)
at loadOnServer (/**/node_modules/redux-async-connect/lib/ReduxAsyncConnect.js:142:16)
it's because XMLHttpRequest
is a built-in object in web browsers but not distributed with Node.
Are there any chance to let the grpc-web works on the Universal Rendering pattern of our website?
thanks for doing this.
I noticed that it supports the 1 request, n responses pattern.
So, if i want to notify a client for whatever reason, i can use this pattern. Its basically exactly like a web socket in terms of patterns at least ?
What would be a use case example of what this library does not support in terms of "client streaming" ?
Hi,
I created a normal gRPC service (not wrapped) based on the exampleserver to test the grpcwebproxy
.
(Here's the source for the gRPC service: https://gist.github.com/pieterlouw/b773b16bd488ac3441ca32a739edb4e9)
I then run the grpcwebproxy
with flag --backend_addr=localhost:9090
I start the example typescript and then get the following in the console.log (which look like it's not handling the CORS and there's a HTTP 500):
dev-server.js:49 [HMR] Waiting for update signal from WDS...
:8443/examplecom.library.BookService/GetBook Failed to load resource: the server responded with a status of 500 ()
:8443/examplecom.library.BookService/GetBook Failed to load resource: the server responded with a status of 500 ()
localhost/:1 Fetch API cannot load https://localhost:8443/examplecom.library.BookService/GetBook. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://localhost:8082' is therefore not allowed access. The response had HTTP status code 500. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
index.ts:22 getBook.onEnd 13 Response closed without headers BrowserHeaders
:8443/examplecom.library.BookService/QueryBooks Failed to load resource: the server responded with a status of 500 ()
:8443/examplecom.library.BookService/QueryBooks Failed to load resource: the server responded with a status of 500 ()
localhost/:1 Fetch API cannot load https://localhost:8443/examplecom.library.BookService/QueryBooks. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://localhost:8082' is therefore not allowed access. The response had HTTP status code 500. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
bundle.js:4889 queryBooks.onEnd 13 Response closed without headers BrowserHeaders
bundle.js:4939 [WDS] Hot Module Replacement enabled.
bundle.js:4943 [WDS] Disconnected!
I looked around in the main.go
and changed the servingServer
Handler to this:
servingServer := http.Server{
WriteTimeout: *flagHttpMaxWriteTimeout,
ReadTimeout: *flagHttpMaxReadTimeout,
Handler: http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
wrappedGrpc.ServeHTTP(resp, req)
//if wrappedGrpc.IsGrpcWebRequest(req) || wrappedGrpc.IsAcceptableGrpcCorsRequest(req) {
// wrappedGrpc.HandleGrpcWebRequest(resp, req)
//}
//resp.WriteHeader(http.StatusNotImplemented)
}),
}
When I rebuild and ran the grpcwebproxy
and ran the typescript I received the following panic from grpcwebproxy
:
panic: interface conversion: *proxy.frame is not proto.Message: missing method ProtoMessage
Full trace:
INFO[0000] listening for http_tls on: [::]:8443
INFO[0000] listening for http on: [::]:8080
panic: interface conversion: *proxy.frame is not proto.Message: missing method ProtoMessage
goroutine 46 [running]:
google.golang.org/grpc.protoCodec.marshal(0x867520, 0xc4201baa00, 0xc4201be5b0, 0x934a4, 0x0, 0x1, 0x5fdd7cfcac48351c, 0xb70ce0)
$GOPATH/src/google.golang.org/grpc/codec.go:73 +0x45
google.golang.org/grpc.protoCodec.Marshal(0x867520, 0xc4201baa00, 0x410dc2, 0xc4201baa60, 0x20, 0x18, 0x8dcec0)
$GOPATH/src/google.golang.org/grpc/codec.go:88 +0x73
google.golang.org/grpc.(*protoCodec).Marshal(0xbcd258, 0x867520, 0xc4201baa00, 0x8a1980, 0xc4201baa60, 0x0, 0x7f4c6f920960, 0x0)
<autogenerated>:35 +0x59
google.golang.org/grpc.encode(0xb74c20, 0xbcd258, 0x867520, 0xc4201baa00, 0x0, 0x0, 0x0, 0x0, 0xc4201dce11, 0x1e, ...)
$GOPATH/src/google.golang.org/grpc/rpc_util.go:254 +0x2f9
google.golang.org/grpc.(*clientStream).SendMsg(0xc4201d4b00, 0x867520, 0xc4201baa00, 0x0, 0x0)
$GOPATH/src/google.golang.org/grpc/stream.go:352 +0x11a
github.com/mwitkow/grpc-proxy/proxy.(*handler).forwardServerToClient.func1(0xb77020, 0xc4201ba8c0, 0xc4201ac9c0, 0xb77080, 0xc4201d4b00)
$GOPATH/src/github.com/mwitkow/grpc-proxy/proxy/handler.go:155 +0xb3
created by github.com/mwitkow/grpc-proxy/proxy.(*handler).forwardServerToClient
$GOPATH/src/github.com/mwitkow/grpc-proxy/proxy/handler.go:160 +0x89
Pieter
It looks like the Serve HTTP does not currently support vanilla HTTP2 gRPC requests.
I propose changing the ServeHTTP to check defer to grpcServer.ServeHTTP when the request is HTTP2.
It should look something like this:
func (w *WrappedGrpcServer) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
if r.ProtoMajor == 2 && strings.Contains(r.Header.Get("Content-Type"), "application/grpc") {
w.grpcServer.ServeHTTP(w, r)
} else if w.IsAcceptableGrpcCorsRequest(req) || w.IsGrpcWebRequest(req) {
w.corsWrapper.Handler(http.HandlerFunc(w.HandleGrpcWebRequest)).ServeHTTP(resp, req)
return
}
w.server.ServeHTTP(resp, req)
}
So - is this approach ok? If I code it, will it get merged?
go get -u github.com/improbable-eng/grpc-web/go/grpcwebproxy
../github.com/improbable-eng/grpc-web/go/grpcwebproxy/main.go:91: cannot use logger (type *"github.com/sirupsen/logrus".Entry) as type "github.com/grpc-ecosystem/go-grpc-middleware/vendor/github.com/sirupsen/logrus".Entry in argument to grpc_logrus.ReplaceGrpcLogger
../github.com/improbable-eng/grpc-web/go/grpcwebproxy/main.go:101: cannot use director (type func("golang.org/x/net/context".Context, string) ("google.golang.org/grpc".ClientConn, error)) as type proxy.StreamDirector in argument to proxy.TransparentHandler
../github.com/improbable-eng/grpc-web/go/grpcwebproxy/main.go:103: cannot use logger (type *"github.com/sirupsen/logrus".Entry) as type *"github.com/grpc-ecosystem/go-grpc-middleware/vendor/github.com/sirupsen/logrus".Entry in argument to grpc_logrus.UnaryServerInterceptor
../github.com/improbable-eng/grpc-web/go/grpcwebproxy/main.go:103: cannot use grpc_prometheus.UnaryServerInterceptor (type func("golang.org/x/net/context".Context, interface {}, *"google.golang.org/grpc".UnaryServerInfo, "google.golang.org/grpc".UnaryHandler) (interface {}, error)) as type "github.com/grpc-ecosystem/go-grpc-middleware/vendor/google.golang.org/grpc".UnaryServerInterceptor in argument to grpc_middleware.WithUnaryServerChain
../github.com/improbable-eng/grpc-web/go/grpcwebproxy/main.go:105: cannot use grpc_middleware.WithUnaryServerChain(grpc_logrus.UnaryServerInterceptor(logger), grpc_prometheus.UnaryServerInterceptor) (type "github.com/grpc-ecosystem/go-grpc-middleware/vendor/google.golang.org/grpc".ServerOption) as type "google.golang.org/grpc".ServerOption in argument to "google.golang.org/grpc".NewServer
../github.com/improbable-eng/grpc-web/go/grpcwebproxy/main.go:107: cannot use logger (type *"github.com/sirupsen/logrus".Entry) as type *"github.com/grpc-ecosystem/go-grpc-middleware/vendor/github.com/sirupsen/logrus".Entry in argument to grpc_logrus.StreamServerInterceptor
../github.com/improbable-eng/grpc-web/go/grpcwebproxy/main.go:107: cannot use grpc_prometheus.StreamServerInterceptor (type func(interface {}, "google.golang.org/grpc".ServerStream, *"google.golang.org/grpc".StreamServerInfo, "google.golang.org/grpc".StreamHandler) error) as type "github.com/grpc-ecosystem/go-grpc-middleware/vendor/google.golang.org/grpc".StreamServerInterceptor in argument to grpc_middleware.WithStreamServerChain
../github.com/improbable-eng/grpc-web/go/grpcwebproxy/main.go:109: cannot use grpc_middleware.WithStreamServerChain(grpc_logrus.StreamServerInterceptor(logger), grpc_prometheus.StreamServerInterceptor) (type "github.com/grpc-ecosystem/go-grpc-middleware/vendor/google.golang.org/grpc".ServerOption) as type "google.golang.org/grpc".ServerOption in argument to "google.golang.org/grpc".NewServer
Hi,
Is it possible to use the grpc-web client with the Java impl grpc-java (instead of the go server, basically) ?
Has anyone successfully managed to make both talk to each other ?
If so, would there be an example anywhere ?
Thanks a lot, kinda lost here.
Here is my proto:
syntax = "proto3";
package helloworld;
service Greeter {
rpc SayHelloStream (HelloRequest) returns (stream HelloReply) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
And here is the server implementation:
func (s *server) SayHelloStream(in *proto.HelloRequest, stream proto.Greeter_SayHelloStreamServer) error {
for j := 0; j <= 10; j++ {
if err := stream.Send(&proto.HelloReply{Message: "Hello " + in.Name}); err != nil {
return err
}
time.Sleep(1000 * time.Millisecond)
}
return nil
}
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
grpcServer := grpc.NewServer()
proto.RegisterGreeterServer(grpcServer, &server{})
wrappedGrpc := grpcweb.WrapServer(grpcServer)
srv := &http.Server{
Handler: http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
wrappedGrpc.ServeHttp(resp, req)
}),
}
// tls certs
srv.Serve(lis)
}
Problem/Question:
https://help.github.com/articles/creating-releases/
We should have a branch for a release + a set of release notes in the Releases page:
https://github.com/c4milo/github-release
https://github.com/aktau/github-release/releases
may be helpful.
We should definitely package the build of grpc-proxy for linux like that.
Hello,
After solving the TLS certs related erros, I'm now sending a fetch request to the grpcwebproxy using:
fetch('https://localhost:8443/package.service/method', {
method: 'POST',
mode: 'no-cors',
headers: {
'Content-Type': 'application/grpc-web',
'X-GRPC-WEB': '1',
},
body: Message.encode(message).finish(),
})
But I get a 501 status reply, and no reaction in my grpc server log.
So is there a way to show the debug log from the grpcwebproxy in the console? Or what are the debug capabilities of grpcwebproxy?
Thank you :)
I'm trying to create an Angular 4 webapp that displays the data retrieved in the grpc call. But, I'm having a heck of a time figuring out how to do it -- likely because I'm not very familiar with typescript/js. I'd appreciate a pointer on how I can get this to work.
Given the getBook
example:
function getBook() {
const getBookRequest = new GetBookRequest();
getBookRequest.setIsbn(60929871);
grpc.unary(BookService.GetBook, {
request: getBookRequest,
host: host,
onEnd: res => {
const { status, statusMessage, headers, message, trailers } = res;
console.log("getBook.onEnd.status", status, statusMessage);
console.log("getBook.onEnd.headers", headers);
if (status === Code.OK && message) {
console.log("getBook.onEnd.message", message.toObject());
//document.write(message.toString());
}
console.log("getBook.onEnd.trailers", trailers);
queryBooks();
}
});
}
I can see the json object being displayed in the console log, but I can't figure out how to return that data so I can bind it to an Angular component and display it in the browser. I've tried something like this:
function getBook(): object {
var result: object = {};
const getBookRequest = new GetBookRequest();
getBookRequest.setIsbn(60929871);
grpc.unary(BookService.GetBook, {
request: getBookRequest,
host: host,
onEnd: res => {
const { status, statusMessage, headers, message, trailers } = res;
console.log("getBook.onEnd.status", status, statusMessage);
console.log("getBook.onEnd.headers", headers);
if (status === Code.OK && message) {
console.log("getBook.onEnd.message", message.toObject());
result = message.toObject()
}
console.log("getBook.onEnd.trailers", trailers);
queryBooks();
}
});
return result
}
But, result
is always empty, which I gather is because the grpc.unary
call is asynchronous. I've also tried creating an Observable
, but I still ended up with an empty value.
I've been trying to figure this out for three days and I am at a loss. Any pointers on how to return the retrieved data so I can bind it in my browser would be much appreciated.
This is a proposal for a debugger interface in grpc-web-client. The intent is to make the current console based debugger extensible and allow clients to implement their own version of the debugger. The driving factor is to improve the currently tedious debugging experience where grpc-web requests shown in the Network tab are not properly serialized and hard to inspect. The proposed interface allows for an extension to be build for Chrome & Firefox to expose grpc-web requests similarly to the Network tab in Chrome.
This document is an aimed athelping shape the debugger interface and get feedback on the proposed changes.
The interface proposed consists of a DebuggerProvider
and a Debugger
.
The provider is responsible for supplying an instance of a debugger to be used in a particular request. Additionally, it can implement supplemental functionality such as tracking of requests or recording request history.
export interface DebuggerProvider {
// Obtain an instance of a debugger.
// A convenience proxy allowing the provider to implement additional functionality
// such as tracking history of requests
getInstanceForRequest(id: number): Debugger;
}
The Debugger
implements callback methods for the lifecycle of a grpc-web request.
// Implements callbacks for grpc-web request/response lifecycle events
export interface Debugger {
// Called just before a request is fired, called only once
onRequestStart(host: string, method: MethodDefinition): void;
// Called just before a request is fired, called only once
onRequestHeaders(headers: BrowserHeaders): void;
// Called with the request payload, potentially called multiple times with request streams
onRequestMessage(payload: Message): void;
// Called when response headers are available, called once multiple times
// This is a low level method intended to debug byte serialization
onResponseHeaders(headers: BrowserHeaders, httpStatus: number): void;
// Called with each received chunk
onResponseChunk?(chunk: Chunk[], chunkBytes: Uint8Array): void;
// Called with each response message, called multiple times with response streams
onResponseMessage(payload: Message): void;
// Called with response trailers, called once
onResponseTrailers(metadata: BrowserHeaders): void;
// Called when a request completes, called once
onResponseEnd(grpcStatus: Code | null): void;
// Called with any error occuring in the flow, potentially called multiple times
onError(code: Code, err: Error): void;
}
export class ConsoleDebuggerProvider implements DebuggerProvider {
getInstanceForRequest(id: number): Debugger {
return new ConsoleDebugger(id);
}
}
export class ConsoleDebugger implements Debugger {
readonly id: number;
constructor(id: number) {
this.id = id;
}
onRequestStart(host: string, method: MethodDefinition): void {
debug(`gRPC-Web #${this.id}: Making request to ${host} for ${method.service.serviceName}.${method.methodName}`, method);
}
onRequestHeaders(headers: BrowserHeaders): void {
debug(`gRPC-Web #${this.id}: Headers:`, headers);
}
onRequestMessage(payload: Message): void {
debug(`gRPC-Web #${this.id}: Request message:`, payload.toObject());
}
onResponseHeaders(headers: BrowserHeaders, httpStatus: number) {
debug(`gRPC-Web #${this.id}: Response headers:`, headers, 'HTTP Status:', httpStatus);
}
onResponseMessage(payload: Message): void {
debug(`gRPC-Web #${this.id}: Response message:`, payload.toObject());
}
onResponseTrailers(metadata: BrowserHeaders): void {
debug(`gRPC-Web #${this.id}: Response trailers:`, metadata);
}
onResponseEnd(grpcStatus: Code | any): void {
debug(`gRPC-Web #${this.id}: Finished with status:`, grpcStatus);
}
onError(code: Code, err: Error): void {
debug(`gRPC-Web #${this.id}: Error. Code:`, code, 'Error:', err);
}
}
In order to allow clients a custom implementation of a debugger, an API must be exposed to allow the registration, retrieval and de-registration of debuggers. The following section discusses possible scenarios of achieving this. When addressing this problem, it is important to consider a scenario where an implementation is not immediately available when an application executes, ie. extension loaded when a user opens developer tools.
In this option, the client is required to explictly include any required debuggers in user code. An example might look as follows:
grpc.registerDebugger(new ConsoleDebuggerProvider());
// extension debugger exposes itself on the window as window.__GRPC_WEB_DEVTOOLS__
if ((window as any).__GRPC_WEB_DEVTOOLS__) {
grpc.registerDebugger((window as any).__GRPC_WEB_DEVTOOLS__);
}
Grpc-web-client reads from a specific global variable containing a list of debuggers to use. This can be made to work in NodeJS as well.
(function (debuggers) {
debuggers.push(new ShinyDebuggerProvider());
window.__GRPC_WEB_DEBUGGERS__ = debuggers;
})(window.__GRPC_WEB_DEBUGGERS__ || []);
grpc
on the global scopeIn order to implement the debugger callbacks, we dispatch individual callbacks inside grpc-web-client
's invoke
method. For example:
const transportOptions: TransportOptions = {
// ...
onHeaders: (headers: Metadata, status: number) => {
detach(() => debugger.onRequestHeaders(headers));
// rest omitted
}
// ...
}
To simplify execution of callbacks for multiple debuggers we can utilize a proxy implementation of the Debugger
interface which dispatches to all registered debuggers. Example here
Currently, we use a debug
property on a request invocation to determine if we should log debug information. This flag would become obsolete and could be removed/depracted.
What do you think? Suggestions & improvements are extremely welcome.
@jonnyreeves @MarcusLongmuir @mwitkow
OBSERVATION
Right now, cancelling a request only propagates to the upstream gRPC server on a "streaming call" after one result was received (because then the reader is available). Cancellation of "unary calls" doesn't propagate to the upstream gRPC server at all.
REASON
Currently, the only away to abort a "fetch" is to cancel the reader, which is only possible after at least one FRAME has been received by the browser (since then you get the reader instance).
(The "fetch" standard will introduce "abort" soon. Some browser already have it, but it might take a while for this to be implemented in all browser.)
PROPOSAL
The grpc-web-proxy should send an empty frame downstream to the client at the beginning in order to trigger the reader being created at the client so that "cancel" is propagated.
Because sending an empty frame might be overhead, I would propose that grpc-web-proxy sends an empty frame with some delay (500ms), i.e. only if the upstream server isn't responding within a certain timeframe, an empty frame is send downstream to the web client.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.