You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何发送Host头与目标地址不同的Java HTTP请求?

发送自定义Host头的HTTP请求(Host与目标地址不一致)的实现方案

问题背景

需要发送HTTP请求,要求请求的Host头与实际连接的目标地址不同,已知变量如下:

String host = "https://example.com/something";
String destination_address = "https://8.8.8.8";
String http_version = "HTTP/2";
String http_method = "POST";
boolean follow_redirects = true;

当前使用Apache Http-Client-5的代码(存在逻辑问题):

H2AsyncClientBuilder builder_2 = HttpAsyncClients.customHttp2();

if (follow_redirects) {
    builder_2.setRedirectStrategy(new DefaultRedirectStrategy());
}

// 错误:builder_1未定义,且用代理方式处理目标地址是错误逻辑
if (!(Objects.equals(destination_address, host))) {
    builder_1.setProxy(HttpHost.create(destination_address));
}

CloseableHttpAsyncClient client = HttpAsyncClients.createDefault();
client = builder_2.build();
client.start();

// POST请求部分
http_request = SimpleRequestBuilder.post(host)
                .setBody(request_body, ContentType.TEXT_PLAIN)
                .setHeaders(request_headers)
                .build();

Future<SimpleHttpResponse> future = client.execute(http_request, null);
SimpleHttpResponse http_response = future.get();
client.close(CloseMode.GRACEFUL);

可行实现方案

方案一:修正Apache HttpClient 5异步HTTP/2实现

原代码核心问题是错误使用代理逻辑,正确做法是直接连接到destination_address,同时手动设置Host头为host中的域名部分。

修正后的代码:

import org.apache.hc.client5.http.async.methods.SimpleHttpRequest;
import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
import org.apache.hc.client5.http.impl.nio.H2AsyncClientBuilder;
import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.HttpHost;

import java.net.URI;
import java.util.concurrent.Future;

// 解析目标地址和Host信息
HttpHost targetHost = HttpHost.create(destination_address);
URI hostUri = URI.create(host);
String targetPath = hostUri.getPath() + (hostUri.getQuery() != null ? "?" + hostUri.getQuery() : "");
String customHostHeader = hostUri.getHost() + (hostUri.getPort() != -1 ? ":" + hostUri.getPort() : "");

// 构建HTTP/2异步客户端
H2AsyncClientBuilder builder = HttpAsyncClients.customHttp2();
if (follow_redirects) {
    builder.setRedirectStrategy(new DefaultRedirectStrategy());
}
CloseableHttpAsyncClient client = builder.build();
client.start();

// 构建POST请求
SimpleHttpRequest httpRequest = SimpleRequestBuilder.post()
        .setHttpHost(targetHost)
        .setPath(targetPath)
        // 手动设置自定义Host头
        .setHeader("Host", customHostHeader)
        .setBody(request_body, ContentType.TEXT_PLAIN)
        .setHeaders(request_headers)
        .build();

// 执行请求
Future<SimpleHttpResponse> future = client.execute(httpRequest, HttpClientContext.create(), null);
SimpleHttpResponse response = future.get();

// 关闭客户端
client.close(CloseMode.GRACEFUL);

关键说明:

  • 从host中提取实际请求路径和自定义Host头值
  • 直接指定请求的目标HttpHost为destination_address
  • 手动添加Host头覆盖默认值

方案二:Apache HttpClient 5同步HTTP/2实现

如果不需要异步处理,可使用同步版本:

import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.nio.H2ClientBuilder;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.io.entity.StringEntity;

import java.net.URI;

// 解析目标和Host信息
HttpHost targetHost = HttpHost.create(destination_address);
URI hostUri = URI.create(host);
String targetPath = hostUri.getPath() + (hostUri.getQuery() != null ? "?" + hostUri.getQuery() : "");
String customHostHeader = hostUri.getHost() + (hostUri.getPort() != -1 ? ":" + hostUri.getPort() : "");

// 构建同步HTTP/2客户端
H2ClientBuilder builder = HttpClients.customHttp2();
if (follow_redirects) {
    builder.setRedirectStrategy(new DefaultRedirectStrategy());
}
CloseableHttpClient client = builder.build();

// 构建POST请求
HttpPost httpPost = new HttpPost(targetPath);
httpPost.setEntity(new StringEntity(request_body, ContentType.TEXT_PLAIN));
httpPost.setHeader("Host", customHostHeader);
// 添加其他请求头
if (request_headers != null) {
    httpPost.setHeaders(request_headers);
}

// 执行请求
try (CloseableHttpClient c = client) {
    var response = c.execute(targetHost, httpPost);
    // 处理响应
}

方案三:使用OkHttp实现

OkHttp对HTTP/2支持良好,处理自定义Host头更简洁:

import okhttp3.*;

import java.io.IOException;

// 解析目标地址和Host信息
HttpUrl targetUrl = HttpUrl.parse(destination_address);
HttpUrl hostUrl = HttpUrl.parse(host);
assert targetUrl != null && hostUrl != null;

// 构建请求路径:保留host中的路径和查询参数
String targetPath = hostUrl.encodedPath() + (hostUrl.encodedQuery() != null ? "?" + hostUrl.encodedQuery() : "");
HttpUrl finalTargetUrl = targetUrl.newBuilder()
        .encodedPath(targetPath)
        .build();

// 构建OkHttpClient
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
if (follow_redirects) {
    clientBuilder.followRedirects(true);
}
// 强制优先使用HTTP/2
clientBuilder.protocols(java.util.List.of(Protocol.HTTP_2, Protocol.HTTP_1_1));
OkHttpClient client = clientBuilder.build();

// 构建请求,手动设置Host头
Request request = new Request.Builder()
        .url(finalTargetUrl)
        .method(http_method, RequestBody.create(request_body, MediaType.get("text/plain")))
        .header("Host", hostUrl.host() + (hostUrl.port() != -1 ? ":" + hostUrl.port() : ""))
        // 添加其他请求头
        .headers(Headers.of(request_headers))
        .build();

// 执行请求
try (Response response = client.newCall(request).execute()) {
    // 处理响应
} catch (IOException e) {
    e.printStackTrace();
}

内容的提问来源于stack exchange,提问作者netcat_dd

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 18:42:49