Skip to content

fix(transport): add HTTP/2 to HTTP/1.1 automatic fallback for connect…#1340

Open
Mrjyw wants to merge 1 commit into
agentscope-ai:mainfrom
Mrjyw:fix/http2-http1-fallback
Open

fix(transport): add HTTP/2 to HTTP/1.1 automatic fallback for connect…#1340
Mrjyw wants to merge 1 commit into
agentscope-ai:mainfrom
Mrjyw:fix/http2-http1-fallback

Conversation

@Mrjyw
Copy link
Copy Markdown

@Mrjyw Mrjyw commented May 5, 2026

When HTTP/2 connections are dropped by cloud infrastructure
(e.g. Alibaba Cloud SLB GOAWAY, RST_STREAM due to rate limiting),the transport now automatically retries the request with HTTP/1.1
instead of failing immediately. Previously, such connection-level
errors propagated directly to the caller with no protocol fallback.

Fixes #1287

1.0.12-SNAPSHOT

Background: Alibaba Cloud SLB/ALB enforces a default limit of concurrent
streams per HTTP/2 connection. When this limit is exceeded, the load balancer sends
GOAWAY or RST_STREAM frames, causing the JDK HttpClient to throw IOExceptions without
an HTTP status code. Other cloud providers (Tencent Cloud CLB, Huawei Cloud ELB) and
enterprise proxies exhibit similar behavior. JDK HttpClient's built-in ALPN
negotiation cannot handle these mid-connection failures since the HTTP/2 connection
was already successfully negotiated.

Changes:

  • JdkHttpTransport: Added http1_1Client field, built eagerly in all three
    constructors via buildClient(config, HttpVersion.HTTP_1_1).

  • execute(): Catches HttpTransportException with no status code when HTTP/2 is
    configured, then retries via doSend(http1_1Client, jdkRequest). If the fallback
    also fails, the original error is thrown to preserve the root cause.

  • stream(): Added onErrorResume in the reactive chain that catches connection-
    level errors (IOException or HttpTransportException without status code) and
    retries with the HTTP/1.1 client via sendAsyncStream().

  • Extracted doSend() and sendAsyncStream() helpers that accept a HttpClient
    parameter, making both protocol paths share the same execution logic.

  • buildClient() overloaded to accept an explicit HttpVersion parameter.

  • Added 7 tests in JdkHttpTransportTest covering the full decision tree:
    HTTP/2 fallback success (execute + stream), HTTP/1.1 normal success (execute +
    stream), HTTP/1.1 no fallback, HTTP/2 no fallback for HTTP errors, and fallback
    failure propagating original error.

  • Code has been formatted with mvn spotless:apply

  • All tests are passing (mvn test)

  • Javadoc comments are complete and follow project conventions

  • Related documentation has been updated

  • Code is ready for review

@Mrjyw Mrjyw requested a review from a team May 5, 2026 08:36
…ion errors

When HTTP/2 connections are dropped by cloud infrastructure
(e.g. Alibaba Cloud SLB GOAWAY, RST_STREAM due to rate limiting),the transport now automatically retries the request with HTTP/1.1
instead of failing immediately. Previously, such connection-level
errors propagated directly to the caller with no protocol fallback.

Fixes agentscope-ai#1287

1.0.12-SNAPSHOT

**Background:** Alibaba Cloud SLB/ALB enforces a default limit of concurrent
streams per HTTP/2 connection. When this limit is exceeded, the load balancer sends
GOAWAY or RST_STREAM frames, causing the JDK HttpClient to throw IOExceptions without
an HTTP status code. Other cloud providers (Tencent Cloud CLB, Huawei Cloud ELB) and
enterprise proxies exhibit similar behavior. JDK HttpClient's built-in ALPN
negotiation cannot handle these mid-connection failures since the HTTP/2 connection
was already successfully negotiated.

**Changes:**

- `JdkHttpTransport`: Added `http1_1Client` field, built eagerly in all three
  constructors via `buildClient(config, HttpVersion.HTTP_1_1)`.
- `execute()`: Catches `HttpTransportException` with no status code when HTTP/2 is
  configured, then retries via `doSend(http1_1Client, jdkRequest)`. If the fallback
  also fails, the original error is thrown to preserve the root cause.
- `stream()`: Added `onErrorResume` in the reactive chain that catches connection-
  level errors (IOException or HttpTransportException without status code) and
  retries with the HTTP/1.1 client via `sendAsyncStream()`.
- Extracted `doSend()` and `sendAsyncStream()` helpers that accept a `HttpClient`
  parameter, making both protocol paths share the same execution logic.
- `buildClient()` overloaded to accept an explicit `HttpVersion` parameter.
- Added 7 tests in `JdkHttpTransportTest` covering the full decision tree:
  HTTP/2 fallback success (execute + stream), HTTP/1.1 normal success (execute +
  stream), HTTP/1.1 no fallback, HTTP/2 no fallback for HTTP errors, and fallback
  failure propagating original error.

- [x] Code has been formatted with `mvn spotless:apply`
- [x] All tests are passing (`mvn test`)
- [x] Javadoc comments are complete and follow project conventions
- [ ] Related documentation has been updated
- [x] Code is ready for review
@Mrjyw Mrjyw force-pushed the fix/http2-http1-fallback branch from c5027a8 to f567fd8 Compare May 6, 2026 14:06
@codecov
Copy link
Copy Markdown

codecov Bot commented May 6, 2026

Codecov Report

❌ Patch coverage is 83.33333% with 7 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...ntscope/core/model/transport/JdkHttpTransport.java 83.33% 1 Missing and 6 partials ⚠️

📢 Thoughts on this report? Let us know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: OpenAIChatModel Http2 有时候调用不通大模型,建议设置自动降级功能,阿里云的服务器默认会对Http2进行限流

1 participant