Socket流转发异常:转发HTTP请求后未收到Web服务器响应
HTTP代理收不到服务器响应的问题修复
我做了一个HTTP请求监听程序,需求是:从客户端Socket(Socket1)的InputStream提取数据后,转发到连接Web服务器的Socket(Socket2)的OutputStream;再把Web服务器返回的Socket2的InputStream回传给Socket1的OutputStream。目前Web服务器能成功收到请求,但我这边收不到响应。查资料说要关闭Socket输出流后再读输入流,我试了调用socket.shutdownOutput(),但问题还是没解决。相关代码如下:
原监听方法代码
private static void runHttpListener(Boolean simulate){ try { ServerSocket server = new ServerSocket(PORT_HTTP_REQUEST); System.out.println("HTTP listener active on Port "+PORT_HTTP_REQUEST); boolean keepAlive = true; while (keepAlive) { //Empfangen und auslesen Socket socketReceivingProxy = server.accept(); System.out.println("HTTP-Listener: Accepted client connection"); InputStream proxyInputStream = socketReceivingProxy.getInputStream(); OutputStream proxyOutputStream = socketReceivingProxy.getOutputStream(); //TODO: extract information from stream //forward InputStream result = sendHttpRequestToDestination(proxyInputStream, simulate); result.transferTo(proxyOutputStream); result.close(); proxyOutputStream.close(); socketReceivingProxy.close(); } server.close(); System.out.println("HTTP listener closed"); } catch (Exception e) { e.printStackTrace(); } }
原转发方法代码
private static InputStream sendHttpRequestToDestination(InputStream incomingRequest, Boolean simulate){ try{ Socket socketForwardingWebapp = new Socket(simulate?URL_WEB_SERVER_SIMULATION:URL_WEB_SERVER, simulate?PORT_WEB_SERVER_SIMULATION:PORT_WEB_SERVER); System.out.println("HTTP-Forwarding: Created socket "+socketForwardingWebapp.getInetAddress()+":"+socketForwardingWebapp.getPort()); InputStream webappInputStream = socketForwardingWebapp.getInputStream(); OutputStream outputStream = socketForwardingWebapp.getOutputStream(); if(incomingRequest.available()>0){ System.out.println("Incoming Request can be forwarded"); long bytesTransfered = incomingRequest.transferTo(outputStream); System.out.print("stream copied"); socketForwardingWebapp.shutdownOutput(); System.out.println("Bytes forwareded: "+bytesTransfered); } return webappInputStream; }catch(Exception exc){ exc.printStackTrace(); } return null; }
问题分析
你的代码存在几个关键问题导致收不到响应:
- 错误依赖
available()判断请求数据:incomingRequest.available()>0仅返回当前缓冲区可读取的字节数,并非请求总长度,若请求数据未完全到达,会跳过转发(你这里服务器已收到请求,说明此场景未触发,但逻辑本身存在隐患)。 - 未确保请求数据完全发送:调用
transferTo后未手动flush输出流,部分数据可能滞留在缓冲区,导致服务器未收到完整请求。 - HTTP Keep-Alive阻塞:HTTP/1.1默认启用Keep-Alive,服务器发送响应后不会立即关闭Socket,
transferTo会一直阻塞直到输入流遇到EOF,导致客户端永远收不到响应。 - 资源管理不完整:转发方法中创建的
socketForwardingWebapp未被正确关闭,仅关闭返回的InputStream无法保证Socket被释放,影响服务器响应传输。
修复后的代码
封装资源类(用于传递Socket和InputStream)
private static class SocketInputStreamPair { private final Socket socket; private final InputStream inputStream; public SocketInputStreamPair(Socket socket, InputStream inputStream) { this.socket = socket; this.inputStream = inputStream; } public Socket getSocket() { return socket; } public InputStream getInputStream() { return inputStream; } }
修改后的转发方法
private static SocketInputStreamPair sendHttpRequestToDestination(InputStream incomingRequest, Boolean simulate){ try{ Socket socketForwardingWebapp = new Socket( simulate ? URL_WEB_SERVER_SIMULATION : URL_WEB_SERVER, simulate ? PORT_WEB_SERVER_SIMULATION : PORT_WEB_SERVER ); System.out.println("HTTP-Forwarding: Created socket "+socketForwardingWebapp.getInetAddress()+":"+socketForwardingWebapp.getPort()); InputStream webappInputStream = socketForwardingWebapp.getInputStream(); OutputStream outputStream = socketForwardingWebapp.getOutputStream(); // 直接转发所有请求数据,直到输入流结束,不再依赖available() long bytesTransfered = incomingRequest.transferTo(outputStream); // 手动flush确保所有数据发送到服务器 outputStream.flush(); socketForwardingWebapp.shutdownOutput(); System.out.println("Bytes forwarded: "+bytesTransfered); return new SocketInputStreamPair(socketForwardingWebapp, webappInputStream); }catch(Exception exc){ exc.printStackTrace(); } return null; }
修改后的监听方法
private static void runHttpListener(Boolean simulate){ try (ServerSocket server = new ServerSocket(PORT_HTTP_REQUEST)) { System.out.println("HTTP listener active on Port "+PORT_HTTP_REQUEST); boolean keepAlive = true; while (keepAlive) { try (Socket socketReceivingProxy = server.accept()) { System.out.println("HTTP-Listener: Accepted client connection"); InputStream proxyInputStream = socketReceivingProxy.getInputStream(); OutputStream proxyOutputStream = socketReceivingProxy.getOutputStream(); // 转发请求并获取服务器响应流和对应的Socket SocketInputStreamPair pair = sendHttpRequestToDestination(proxyInputStream, simulate); if (pair == null) { continue; } try (Socket serverSocket = pair.getSocket(); InputStream serverInputStream = pair.getInputStream()) { // 转发服务器响应到客户端 serverInputStream.transferTo(proxyOutputStream); // flush确保响应发送到客户端 proxyOutputStream.flush(); } } catch (Exception e) { e.printStackTrace(); } } System.out.println("HTTP listener closed"); } catch (Exception e) { e.printStackTrace(); } }
额外说明
如果需要支持HTTP/1.1的Keep-Alive,需解析请求和响应的Connection头:
- 若头值为
keep-alive,则保留Socket等待下一次请求 - 若为
close,则关闭Socket
另外,对于chunked编码的响应,需正确解析分块数据,不能仅依赖InputStream的EOF。
内容的提问来源于stack exchange,提问作者Jones
相关产品推荐
相关产品推荐

