diff --git a/javascript/net/grpc/web/grpcwebclientbase.js b/javascript/net/grpc/web/grpcwebclientbase.js index 21afdf05..2c5ea44e 100644 --- a/javascript/net/grpc/web/grpcwebclientbase.js +++ b/javascript/net/grpc/web/grpcwebclientbase.js @@ -74,12 +74,21 @@ GrpcWebClientBase.prototype.rpcCall = function( stream.on('status', function(status) { if (status.code != StatusCode.OK) { callback({ - 'code': status.code, - 'message': status.details + code: status.code, + message: status.details }, null); } }); + stream.on('error', function(error) { + if (error.code != StatusCode.OK) { + callback({ + code: error.code, + message: error.message + }); + } + }); + xhr.headers.set('Content-Type', 'application/grpc-web-text'); xhr.headers.set('X-User-Agent', 'grpc-web-javascript/0.1'); xhr.headers.set('Accept', 'application/grpc-web-text'); diff --git a/javascript/net/grpc/web/grpcwebclientreadablestream.js b/javascript/net/grpc/web/grpcwebclientreadablestream.js index 76dc2249..68d8c063 100644 --- a/javascript/net/grpc/web/grpcwebclientreadablestream.js +++ b/javascript/net/grpc/web/grpcwebclientreadablestream.js @@ -32,6 +32,7 @@ goog.module.declareLegacyNamespace(); const ClientReadableStream = goog.require('grpc.web.ClientReadableStream'); +const ErrorCode = goog.require('goog.net.ErrorCode'); const EventType = goog.require('goog.net.EventType'); const GrpcWebStreamParser = goog.require('grpc.web.GrpcWebStreamParser'); const StatusCode = goog.require('grpc.web.StatusCode'); @@ -85,6 +86,12 @@ const GrpcWebClientReadableStream = function(genericTransportInterface) { */ this.onStatusCallback_ = null; + /** + * @private + * @type {function(...):?|null} The error callback + */ + this.onErrorCallback_ = null; + /** * @private * @type {function(...):?|null} The stream end callback @@ -165,6 +172,26 @@ const GrpcWebClientReadableStream = function(genericTransportInterface) { return; } }); + + events.listen(this.xhr_, EventType.COMPLETE, function(e) { + if (!self.onErrorCallback_) return; + var lastErrorCode = self.xhr_.getLastErrorCode(); + if (lastErrorCode != ErrorCode.NO_ERROR) { + self.onErrorCallback_({ + code: StatusCode.UNAVAILABLE, + message: ErrorCode.getDebugMessage(lastErrorCode) + }); + return; + } + var responseHeaders = self.xhr_.getResponseHeaders(); + if (GRPC_STATUS in responseHeaders && + responseHeaders[GRPC_STATUS] != StatusCode.OK) { + self.onErrorCallback_({ + code: responseHeaders[GRPC_STATUS], + message: responseHeaders[GRPC_STATUS_MESSAGE] + }); + } + }); }; @@ -180,6 +207,8 @@ GrpcWebClientReadableStream.prototype.on = function( this.onStatusCallback_ = callback; } else if (eventType == 'end') { this.onEndCallback_ = callback; + } else if (eventType == 'error') { + this.onErrorCallback_ = callback; } return this; }; diff --git a/net/grpc/gateway/examples/echo/echotest.html b/net/grpc/gateway/examples/echo/echotest.html index 35d09bf7..93a4de8c 100644 --- a/net/grpc/gateway/examples/echo/echotest.html +++ b/net/grpc/gateway/examples/echo/echotest.html @@ -63,8 +63,7 @@ unaryRequest.setMessage(msg); echoService.echoAbort(unaryRequest, {}, function(err, response) { if (err) { - addRightMessage('Error received'); - console.log('Error:', err); + addRightMessage('Error code: '+err.code+' "'+err.message+'"'); console.log('Error code: ' + err.code + (err.code == grpc.web.StatusCode.ABORTED ? ' is ' : ' is not ') + @@ -96,6 +95,9 @@ console.log(status.metadata); } }); + stream.on('error', function(err) { + addRightMessage('Error code: '+err.code+' "'+err.message+'"'); + }); stream.on('end', function() { console.log("stream end signal received"); }); diff --git a/net/grpc/gateway/examples/echo/envoy.yaml b/net/grpc/gateway/examples/echo/envoy.yaml index 494c34bc..886ba5f6 100644 --- a/net/grpc/gateway/examples/echo/envoy.yaml +++ b/net/grpc/gateway/examples/echo/envoy.yaml @@ -28,7 +28,7 @@ static_resources: allow_methods: GET, PUT, DELETE, POST, OPTIONS allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,custom-header-1,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web max_age: "1728000" - allow_credentials: true + expose_headers: custom-header-1,grpc-status,grpc-message enabled: true http_filters: - name: envoy.grpc_web