[Issue 1487] Fix ErrorDecoder not invoked for Apache HttpClient checked exceptions#3338
[Issue 1487] Fix ErrorDecoder not invoked for Apache HttpClient checked exceptions#3338gitshabh wants to merge 1 commit intoOpenFeign:masterfrom
Conversation
b0a9252 to
1c47c11
Compare
|
@velo |
velo
left a comment
There was a problem hiding this comment.
Thanks for picking this up, but I don't think the synthetic-response approach is the right direction. Concerns:
- Misleading status codes:
300for "missing Location header" and500for arbitrary checked exceptions misrepresent what actually happened. ErrorDecoders keying off status will misclassify, and these synthetic codes can collide with real server responses the user already handles. - Silent retry loss: callers previously got
RetryableException(going throughRetryer); now they get a non-retryableFeignException. That is a backwards-incompatible behavior change. - Brittle detection:
cause.getClass().getSimpleName().equals("ProtocolException")should beinstanceof org.apache.http.ProtocolException. String comparison also collides withjava.net.ProtocolException. - Lossy: original cause is reduced to body bytes via
getMessage().getBytes()(platform default charset). ErrorDecoders can't tell what actually went wrong. - Catches too broadly:
!IOException && !RuntimeException && !Errorswallows any checked-exception cause into a fake 500, far wider than "ProtocolException on redirect". reasonfield misuse: that field is the HTTP reason phrase, not an exception class name.- Cross-client inconsistency: only HC4 gets this treatment; hc5/OkHttp/JDK/Java11 still behave differently for the same scenario.
- Test coverage: one test, only the redirect path; the generic 500 branch is untested.
Posting better directions in a separate comment.
|
@gitshabh thanks for the work — to your question, I don't think this is the right approach. Some better directions: 1. Minimal fix at the boundary. Ensure non- try {
HttpResponse httpResponse = client.execute(httpUriRequest);
return toFeignResponse(httpResponse, request);
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new IOException(e);
}That said — 2. If you genuinely want 3. Where the change belongs. If anything is centralized, it belongs in core (e.g., The fundamental issue with the current PR: synthetic HTTP statuses ( |
Problem
When Apache HttpClient throws checked exceptions like ProtocolException (e.g., missing Location header on 303 redirect), the ErrorDecoder was never invoked because the exception occurred during client.execute() before a Response object was created.
Root Cause
The ErrorDecoder interface requires a Response object: [Exception decode(String methodKey, Response response)]. When execution fails with checked exceptions, there's no Response to pass, causing the exception to propagate uncaught and potentially get wrapped in UndeclaredThrowableException.
Solution:
Build Response with appropriate status codes in case of ProtocolException instead of throwing exception so that error decoder can be invoked.