-
Notifications
You must be signed in to change notification settings - Fork 777
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enhance HTTP Status handling #1472
base: master
Are you sure you want to change the base?
Conversation
|
@sampajano any chance to move this PR forward? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@wszydlak Thank you so much for proposing this change with detailed rationales (even with alternatives)!! Appreciate!
I apologize for the late review! — I was out for a few weeks and have been catching up on things :)
Overall i think this change makes a lot of sense!! And i certainly like it better than the alternative solution — since it provides more structured data and can be better accessed programmatically 😃
Regarding your questions:
- Acceptability: Is adding the
httpStatusCode
to theRpcError
object an acceptable enhancement for unary and streaming calls?
I think this is a fairly reasonable improvement to the API!
- Metadata Handling: Should we consider modifying metadata to accept numbers for better handling of HTTP-specific errors?
I'm not quite understanding here. Do you mind elaborate a bit (maybe with examples)?
- Alternative: Is proposed solution ok, or you want to try with proposed alternative?
I like this solution better since the data is more programmatically accessible!
One question tho:
Are you intending to make this "unary only" feature? Why not make this accessible across the board even for streaming then?
From what I could tell, the following maybe the only other missing scenario where we can return an RpcError from xhr errors:
grpc-web/javascript/net/grpc/web/grpcwebclientreadablestream.js
Lines 260 to 264 in b5ff5d3
if (xhrStatusCode != -1) { | |
errorMessage += ', http status code: ' + xhrStatusCode; | |
} | |
self.handleError_(new RpcError(grpcStatusCode, errorMessage)); |
Maybe we could simply add httpStatusCode
here as well?
And one more thing, could we add a simple test?
Maybe just add a new test like this one?
async testRpcError() { |
Again, thank you so much for proposing this improvement! I think it makes much sense and I appreciate your contribution!
Hello, thanks for the response I appreciate that you see this improvement is reasonable.
PR contains also changes for the regular streaming: https://github.com/wszydlak/grpc-web/blob/feature/http-status-on-error/javascript/net/grpc/web/grpcwebclientreadablestream.js#L265
Sure, i mean the types in the grpc-web package: https://github.com/wszydlak/grpc-web/blob/feature/http-status-on-error/packages/grpc-web/index.d.ts#L3 export type Metadata = Record<string, string> & { httpStatusCode?: number }; This will allow us to handle
Sure, if we will decide what should be the final implementation i will also prepare tests 🙂 |
Oh nice! Wonderful! Thanks for reminding me :) I saw that you've put "unary" in PR title and title and hence the question. Do you mind updating that too?
Ahh nice.. I like the idea! Why not! :)
Yes. I'm happy with the solution and will merge it once a test is added! Thanks again! :) |
9ef3774
to
82f7f36
Compare
Hello again @sampajano, coming back with some changes:
I ran the mocha tests and generated test for Please confirm that proposed solution is acceptable and if everything looks good or maybe some changes are required. Additionally, if everything is ok - can we schedule release date of 1.6.0 (assuming this version will contain proposed changes)? |
82f7f36
to
b84dc9c
Compare
@sampajano I reverted commit with change of the submodule. Maybe this should be addressed in separate PR. Waiting for the tests re-run. |
@sampajano I see tests are passing, what are the next steps? |
@wszydlak Hi! My apologies that I was caught up in something and not able to find time for this just yet, and will be out until mid next week. I'll review this as soon as I'm back and will get it merged soon! And yes! We're recently getting some new help on grpc-web now so we'll do a release soon! |
Sure, waiting then for a review 👍 Thanks 🙂 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi! Thanks for the change! I've started to review it and have a first few questions! Thanks!
let contentType = self.xhr_.getStreamingResponseHeader('Content-Type'); | ||
if (!contentType) return; | ||
contentType = contentType.toLowerCase(); | ||
const contentType = (self.xhr_.getStreamingResponseHeader('Content-Type') || '').toLowerCase(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you explain a bit more on the motivation of all these changes (besides just adding the httpStatusCode
in metadata)?
It looks to me that it's altering some existing logic, and I'm not sure if it can cause regressions.
From the PR description, I got the impression that adding httpStatusCode
was all we needed.
Is that not the case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi, already described it above: #1472 (comment)
@@ -257,11 +253,14 @@ class GrpcWebClientReadableStream { | |||
return; | |||
} | |||
let errorMessage = ErrorCode.getDebugMessage(lastErrorCode); | |||
|
|||
const errorMetadata = /** @type {!StatusMetadata} */ ({}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line won't pass closure compilation (it will break internal tests, but not sure why it's not throwing up in tests :)) — since StatusMetadata
is not a defined type in Closure JS.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How then can we define it as a type for Closure JS? How is Metadata
defined in closure js?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this about creating file like this: javascript/net/grpc/web/metadata.js ?
@@ -1,6 +1,9 @@ | |||
declare module "grpc-web" { | |||
|
|||
export interface Metadata { [s: string]: string; } | |||
export type StatusMetadata = Metadata & { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I appreciate the type extension, and i personally prefer this kind of change.
However, since I plan to have this feature only in open source grpc-web, i prefer to make minimal changes to the rest of the API (e.g. in RpcError
, etc.). Would it be possible if you just modify Metadata instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was my first tought, but, Metadata type is used both for input and output to grpc-services. Also i assume that previous definition od Metadata follows this: https://grpc.io/docs/guides/metadata/#overview (keys are string, values are string or binary).
To not make a breaking change for those who rely on Record<string, string>
i created separate Metadata for request statuses (status + error) that additionaly can have new httpStatusCode
property of number type.
I think this is more secure way to handle Metadata for status and error.
Don't see any reason why httpStatusCode
should be valid property for standard messaging (in-out).
That's why i decided to make separate type.
Pull Request: Enhance HTTP Status handling in unary calls
Background
When using gRPC-Web with a reverse proxy like NGINX, there are scenarios where the proxy may return HTTP status codes (e.g.,
503
,505
) without invoking the actual gRPC service. In such cases, the gRPC-Web library throws anRpcError
with aStatusCode.UNKNOWN
. This limits the ability to differentiate between HTTP errors and makes it challenging to implement robust client-side error handling based on specific HTTP statuses.Changes introduced in this PR
Addition of
httpStatusCode
to Errorsgrpcwebclientreadablestream.js
to include thehttpStatusCode
from the XHR object.Enhanced
complete
event for streamingcomplete
event for streaming calls to mirror the unary call changes.httpStatusCode
is now included in metadata when firingstatus
event.Alternatives
As an alternative resolution i can prepare solution similar to this line, so the final result for UNKNOWN error could be handled like:
Example behaviour before and after this change
Before:
Unary call errors always return
RpcError
withStatusCode.UNKNOWN
, irrespective of the HTTP status code.After:
Errors now include the
httpStatusCode
field in metadata, enabling better decision-making on the client side.Example:
Open Questions
httpStatusCode
to theRpcError
object an acceptable enhancement for unary and streaming calls?Why This Change Is Valuable
503
,505
) and gRPC errors, particularly when intermediary layers like NGINX are used.