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

如何在两个Web服务间维持持久连接并建立跨防火墙的双工通信

问题陈述

我需要从防火墙后向外发起SSL连接对接外部云Web服务,且保持该连接开启以实现双工通信,为便于理解,我将该需求拆分为两个阶段如下:

阶段1:实现客户端向云服务的出站连接复用

我有一个安装运行在客户防火墙后的agent,它会通过443端口向外部云Web服务发起连接。
我尝试了两种实现方式:

  • SSL socket客户端
public class SSLSocketClient {
    public static void main(String[] args) throws Exception {
        try {
            SSLSocketFactory factory =
                (SSLSocketFactory)SSLSocketFactory.getDefault();
            SSLSocket socket =
                (SSLSocket)factory.createSocket("mycloud.com", 443);
            socket.setKeepAlive(true);
            
            socket.startHandshake();
            boolean isLive = true;
            
            PrintWriter out = new PrintWriter(
                                  new BufferedWriter(
                                  new OutputStreamWriter(
                                  socket.getOutputStream())));
            
            out.println("GET /some/orgs/myorg HTTP/1.1");
            out.println("Host: mycloud.com");
            out.println("Accept: application/json");
            out.println("X-Api-Key: knwysf24tzeatwk5dwnqa6xh");
            
            out.println();
            out.flush();
    
            /*
             * Make sure there were no surprises
             */
            if (out.checkError())
                System.out.println(
                    "SSLSocketClient:  java.io.PrintWriter error");
    
            /* read response */
            BufferedReader in = new BufferedReader(
                                    new InputStreamReader(
                                    socket.getInputStream()));
    
            String inputLine;
            while ((inputLine = in.readLine()) != null)
                System.out.println(inputLine);
    
            in.close();
            out.close();
            socket.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

该方案中,每次请求响应周期结束后连接就会关闭,每次发起新请求都需要重新建立连接。
为避免重复建连问题,我尝试使用apache commons-httpclient库:

  • 使用apache commons-httpclient库创建HTTP连接
public class HttpClientTest {
    private static int connectionTimeout = 1000;
    private static int socketTimeout = 10000;
    private static String host = "mycloud.com";
    private static int port = 443;
    static boolean  useExpectContinue = true;
    
    @SuppressWarnings("deprecation")
    public static DefaultHttpClient configureClient() {
        HttpParams params = new BasicHttpParams();
        HttpProtocolParams.setUseExpectContinue(params, useExpectContinue);
        HttpConnectionParams
                .setConnectionTimeout(params, connectionTimeout);
        HttpConnectionParams.setSoTimeout(params, socketTimeout);
        HttpConnectionParams.setTcpNoDelay(params, Boolean.TRUE);
    
        String protocol = "https";
        params.setParameter(ClientPNames.DEFAULT_HOST, new HttpHost(host,
                port, protocol));
        DefaultHttpClient client = new DefaultHttpClient(params);
    
        return client;
    }
    
    @SuppressWarnings("deprecation")
    public static void main(String args []) throws IOException {
        String uri = "/idbridge/orgs/cableco_rt";
        
        HttpGet httpGet = new HttpGet(uri);
        httpGet.setHeader("Host",host);
        httpGet.setHeader("Accept","application/json");
        httpGet.setHeader("X-Api-Key","knwysf24tzeatwk5dwnqa6xh");
        
        
        String uriOrg = "/idbridge/orgs";
        
        HttpGet httpGetOrg = new HttpGet(uriOrg);
        httpGetOrg.setHeader("Host",host);
        httpGetOrg.setHeader("Accept","application/json");
        httpGetOrg.setHeader("X-Api-Key","knwysf24tzeatwk5dwnqa6xh");
        @SuppressWarnings("deprecation")
        DefaultHttpClient client = configureClient();
        HttpParams params = client.getParams();
        
        System.out.println("Client connected to -> " + params.getParameter("http.default-host") +"\n ______________________________");
    
        System.out.println("Request -> " + httpGet.getURI()+"\n");
        org.apache.http.HttpResponse rsp = client.execute(httpGet);
        
        
        HttpEntity entity = rsp.getEntity();
        Header[] allHeaders = rsp.getAllHeaders();
        System.out.println("Response"
                + " :  "+EntityUtils.toString(entity,"UTF-8") +"\n______________________________");
        
        
        
        org.apache.http.HttpResponse rspOrg = client.execute(httpGetOrg);
        System.out.println("Request -> " + httpGetOrg.getURI()+"\n");
    
        HttpEntity entityOrg = rspOrg.getEntity();
      Header[] allHeadersOrg = rspOrg.getAllHeaders();
      System.out.println("Response"
            + " :  "+EntityUtils.toString(entityOrg,"UTF-8"));      
    }
}

该方案解决了每次请求都需要重新建连的问题,只需创建一次DefaultHttpClient就可以多次复用。

阶段2:实现连接双工通信,支持云服务反向调用

我第二阶段的问题是要维持该连接,即我的源Web服务按上述方法创建的连接,后续目标Web服务需要发起请求时也可以复用该连接,需要创建某种hook或callback来开启双向通信,也就是双工通信。
为解决该问题我尝试使用了AsyncClientHttpExchange:

public class AsyncClientHttpExchange {
    public static void main(final String[] args) throws Exception {
        CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault();
        try {
            httpclient.start();
            HttpGet request = new HttpGet("http://localhost:9090/connect");
            Future<HttpResponse> future = httpclient.execute(request, null);
            HttpResponse response = future.get();
            System.out.println(EntityUtils.toString(response.getEntity(),"UTF-8") );
            System.out.println("Response: " + response.getStatusLine());
            System.out.println("Shutting down");
        } finally {
            httpclient.close();
        }
        System.out.println("Done");
    }       
}

但该方案仍然无法解决我callback/hook的需求,我需要的正是以下描述的行为:

回调:服务端在完成任务后主动发起调用,切换为客户端角色向原始客户端(此时客户端充当服务端)发起HTTP请求。两端需要共用一套协议约定(比如特定格式的PUT或POST请求)。
希望获得实现该功能的代码参考。

补充用例说明

服务S1和云服务CS2,S1部署在本地机房对接用户源,S1可以从用户源拉取数据发送到云服务CS2(S1可通过443端口向CS2发起出站SSL连接)。后续如果有用户在CS2发起认证请求,CS2需要调用本地S1服务对接用户源完成认证。注意:S1和用户源都处于防火墙后,仅支持S1主动向CS2发起443端口出站SSL连接,请问如何实现CS2按需向防火墙后的S1发起请求?

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 00:24:04