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

如何通过Java实现跨服务器HTTP请求转发及响应处理?

1. 如何通过一台服务器向另一台服务器发送HTTP请求?

在Java开发中,有几种实用的方式可以实现跨服务器的HTTP请求,我给你整理了最常用的几个:

  • Java原生HttpURLConnection:这是JDK自带的工具,无需额外依赖,适合简单的请求场景。比如发送GET请求的示例:

    URL url = new URL("http://目标服务器地址/api");
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    conn.setRequestMethod("GET");
    
    try (BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()))) {
        String line;
        StringBuilder response = new StringBuilder();
        while ((line = in.readLine()) != null) {
            response.append(line);
        }
        System.out.println(response.toString());
    } finally {
        conn.disconnect();
    }
    
  • Java 11+ 内置HttpClient:这是JDK11新增的HTTP客户端,API更简洁,支持同步/异步请求,是当前推荐的方案:

    HttpClient client = HttpClient.newHttpClient();
    HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("http://目标服务器地址/api"))
            .GET()
            .build();
    
    // 同步请求
    HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
    System.out.println(response.body());
    
    // 异步请求
    client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
            .thenApply(HttpResponse::body)
            .thenAccept(System.out::println)
            .join();
    
  • Apache HttpClient:如果需要更复杂的功能(比如连接池管理、重试机制、复杂表单提交),可以使用Apache的HttpClient库,它提供了更灵活的配置选项,不过需要引入Maven依赖。


2. 局域网无公网IP设备通过公网路由服务器转发HTTP请求的Java最优方案

这个场景的核心痛点是:局域网设备没有公网IP,无法直接向外部发起HTTP请求,必须借助有公网访问能力的路由服务器做中转。根据不同的网络环境,我推荐两种最优方案:

方案一:基于HTTP代理的中转(简单易实现)

如果你的局域网设备可以直接访问路由服务器的公网IP和指定端口(防火墙无限制),那么把路由服务器做成HTTP代理服务器是最简单的选择。

实现思路:

  1. 在路由服务器上搭建HTTP代理服务,接收局域网设备的代理请求;
  2. 代理服务将请求转发到目标外部服务器;
  3. 把外部服务器的响应原路返回给局域网设备。

用Spring Boot快速实现通用代理:

可以借助smiley-http-proxy-servlet库快速搭建通用代理,步骤如下:

  1. 引入Maven依赖:
    <dependency>
        <groupId>org.mitre.dsmiley.httpproxy</groupId>
        <artifactId>smiley-http-proxy-servlet</artifactId>
        <version>1.12.1</version>
    </dependency>
    
  2. 配置代理Servlet:
    @Configuration
    public class ProxyConfig {
        @Bean
        public ServletRegistrationBean<HttpProxyServlet> proxyServlet() {
            ServletRegistrationBean<HttpProxyServlet> registrationBean = 
                new ServletRegistrationBean<>(new HttpProxyServlet(), "/proxy/*");
            // 这里可以不固定目标地址,让请求动态指定
            registrationBean.addInitParameter("targetUri", "http://placeholder");
            registrationBean.addInitParameter("log", "true");
            return registrationBean;
        }
    }
    

局域网设备发起请求时,只需将目标地址拼接在代理路径后,比如http://路由服务器公网IP:端口/proxy/http://外部目标服务器/api,代理服务会自动转发并返回响应。

方案二:基于长连接隧道的中转(适用于防火墙限制场景)

如果局域网设备无法直接访问路由服务器的代理端口(比如防火墙只开放特定端口),可以采用长连接隧道的方式:局域网设备先与路由服务器建立持久长连接(比如WebSocket),通过这个隧道传递HTTP请求和响应。

实现思路:

  1. 路由服务器搭建WebSocket服务,接收局域网设备的连接;
  2. 局域网设备通过WebSocket发送包含目标HTTP请求信息(方法、URL、Headers、Body)的消息;
  3. 路由服务器解析消息后,向外部目标服务器发起HTTP请求;
  4. 路由服务器将外部响应封装成消息,通过WebSocket返回给局域网设备;
  5. 局域网设备解析响应并处理业务逻辑。

核心代码示例:

路由服务器端(Spring Boot + WebSocket):

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(new ProxyWebSocketHandler(), "/proxy-ws").setAllowedOrigins("*");
    }
}

@Component
public class ProxyWebSocketHandler extends TextWebSocketHandler {
    private final HttpClient httpClient = HttpClient.newHttpClient();
    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        // 解析局域网设备发送的请求DTO
        ProxyRequest proxyRequest = objectMapper.readValue(message.getPayload(), ProxyRequest.class);
        
        // 构建并发送HTTP请求到外部服务器
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(proxyRequest.getTargetUrl()))
                .method(proxyRequest.getMethod(), HttpRequest.BodyPublishers.ofString(proxyRequest.getBody()))
                .headers(proxyRequest.getHeaders())
                .build();
        
        HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
        
        // 封装响应并发送回设备
        ProxyResponse proxyResponse = new ProxyResponse();
        proxyResponse.setStatusCode(response.statusCode());
        proxyResponse.setHeaders(response.headers().map());
        proxyResponse.setBody(response.body());
        
        session.sendMessage(new TextMessage(objectMapper.writeValueAsString(proxyResponse)));
    }
}

// 请求和响应的DTO定义
class ProxyRequest {
    private String targetUrl;
    private String method;
    private Map<String, String> headers;
    private String body;
    // Getter & Setter 省略
}

class ProxyResponse {
    private int statusCode;
    private Map<String, List<String>> headers;
    private String body;
    // Getter & Setter 省略
}

局域网设备端:

public class ProxyClient {
    public static void main(String[] args) throws Exception {
        WebSocketContainer container = ContainerProvider.getWebSocketContainer();
        String wsUri = "ws://路由服务器公网IP:端口/proxy-ws";
        Session session = container.connectToServer(new Endpoint() {
            @Override
            public void onOpen(Session session, EndpointConfig config) {
                // 构造并发送请求
                ProxyRequest request = new ProxyRequest();
                request.setTargetUrl("http://外部目标服务器/api");
                request.setMethod("POST");
                request.setHeaders(Map.of("Content-Type", "application/json"));
                request.setBody("{\"key\":\"value\"}");
                
                try {
                    session.getBasicRemote().sendText(new ObjectMapper().writeValueAsString(request));
                } catch (IOException e) {
                    e.printStackTrace();
                }
                
                // 监听响应
                session.addMessageHandler(new MessageHandler.Whole<String>() {
                    @Override
                    public void onMessage(String message) {
                        try {
                            ProxyResponse response = new ObjectMapper().readValue(message, ProxyResponse.class);
                            System.out.println("响应状态码:" + response.getStatusCode());
                            System.out.println("响应体:" + response.getBody());
                        } catch (JsonProcessingException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
        }, URI.create(wsUri));
    }
}

方案选择建议:

  • 若网络环境宽松,局域网可直接访问路由服务器代理端口,优先选方案一,开发成本低、维护简单;
  • 若存在防火墙限制,或需要更高的安全性(如请求加密、设备身份校验),选方案二,长连接隧道的穿透性更强,扩展性更好。

额外注意事项:

  • 加入身份验证:避免路由服务器被滥用,比如在代理服务中加入API Key校验,或WebSocket连接时验证设备身份;
  • 处理异常场景:针对连接失败、超时等情况,添加重试和重连机制;
  • 优化性能:使用HTTP连接池复用连接,高并发场景下可改用Netty替代原生WebSocket实现。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 09:21:04