简单的java版http代理
4930 点击·0 回帖
![]() | ![]() | |
![]() | 为了说明http代理的工作机制,我特意写了一个最简单的代理,去掉很多繁杂的功能,并尽可能的使代码量小,源码如下,不清楚http代理机制的朋友参考一下基本就明白了。 [java] /* * $RCSfile: SimpleHttpProxy.java,v $$ * $Revision: 1.1 $ * $Date: 2013-1-9 $ * * Copyright (C) 2008 Skin, Inc. All rights reserved. * * This software is the proprietary information of Skin, Inc. * Use is subject to license terms. */ package test.com.skin.http.proxy; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketTimeoutException; import java.net.URL; /** * <p>Title: SimpleHttpProxy</p> * <p>Description: </p> * <p>Copyright: Copyright (c) 2006</p> * @author xuesong.net * @version 1.0 */ public class SimpleHttpProxy { public static final int PORT = 6666; public static final byte[] CRLF = new byte[]{0x0D, 0x0A}; /** * @param args */ public static void main(String[] args) { ServerSocket socketServer = null; try { socketServer = new ServerSocket(PORT); while(true) { try { final Socket socket = socketServer.accept(); (new Thread(){ public void run(){ SimpleHttpProxy.service(socket); } }).start(); } catch(SocketTimeoutException e) { e.printStackTrace(); } catch(IOException e) { e.printStackTrace(); } } } catch(Exception e) { e.printStackTrace(); } finally { if(socketServer != null) { try { socketServer.close(); } catch(IOException e) { } } } } private static void service(Socket socket) { Socket remote = null; try { socket.setSoTimeout(2000); socket.setKeepAlive(false); InputStream inputStream = socket.getInputStream(); OutputStream outputStream = socket.getOutputStream(); /** * 读取协议头的第一行 * 格式: GET http://www.mytest.com HTTP/1.1 */ byte[] buffer = readLine(inputStream); if(buffer.length < 1) { return; } String header = new String(buffer, "UTF-8"); String[] action = header.split(" "); if(action.length < 3) { return; } String address = action[1]; /** * 目标地址是从http协议的第一行取 * 目标主机应该从协议的Host头里面取,如果Host取不到, 从地址里面取 * 此处为了简化逻辑只从地址里面取host, 因此如果路径不是绝对路径就忽略 */ if(address.startsWith("http://") == false) { return; } System.out.print(header); URL url = new URL(address); String host = url.getHost(); int port = (url.getPort() > -1 ? url.getPort() : 80); remote = new Socket(host, port); InputStream remoteInputStream = remote.getInputStream(); OutputStream remoteOutputStream = remote.getOutputStream(); /** * 某些服务器对协议头必须一次性读完, 例如qq空间 * 因此此处先读出协议头, 并且一次写入, 写入之后必须flush * 否则就跳转到QQ首页了 */ long contentLength = -1L; ByteArrayOutputStream bos = new ByteArrayOutputStream(); bos.write(buffer, 0, buffer.length); /** * 读取协议头 * 也可以不读取协议头, 而是直接把inputStream写入到remoteOutputStream * 为了兼容某些服务器, 此处简单的读取一下协议头 */ while((buffer = readLine(inputStream)).length > 0) { header = new String(buffer, "UTF-8").trim(); if(header.length() < 1) { break; } if(header.startsWith("Content-Length:")) { try { contentLength = Long.parseLong(header.substring(15).trim()); } catch(NumberFormatException e){} } bos.write(buffer, 0, buffer.length); } /** 协议头和主体之间的空行 */ bos.write(CRLF); remoteOutputStream.write(bos.toByteArray()); remoteOutputStream.flush(); /** 如果存在contentLength */ if(contentLength > 0) { copy(inputStream, remoteOutputStream, 4096, contentLength); } try { /** * 将目标主机返回的数据写入到客户端 * 此处应该检查一下Content-Length, 并且根据Content-Length来决定要写入多少数据 * 不过很多服务器经常会不返回Content-Length, * 没有Content-Length, read函数会一直读取 * 因此使用timeout来解决阻塞的问题 * 超时的时候自动退出线程, 否则该线程就无法释放了 */ remote.setSoTimeout(10000); copy(remoteInputStream, outputStream, 4096); } catch(SocketTimeoutException e) { } catch(Exception e) { e.printStackTrace(); } } catch(Exception e) { e.printStackTrace(); } finally { try { if(socket != null) { socket.close(); } } catch(IOException e) { } try { if(remote != null) { remote.close(); } } catch(IOException e) { e.printStackTrace(); } } } public static byte[] readLine(InputStream stream) throws IOException { int b = -1; ByteArrayOutputStream bos = new ByteArrayOutputStream(2048); while((b = stream.read()) != -1) { if(b == '\n') { bos.write(b); break; } bos.write(b); } return bos.toByteArray(); } public static void copy(InputStream inputStream, OutputStream outputStream, int bufferSize) throws IOException { int length = 0; byte[] buffer = new byte[bufferSize]; while((length = inputStream.read(buffer, 0, bufferSize)) > -1) { outputStream.write(buffer, 0, length); } outputStream.flush(); } public static void copy(InputStream inputStream, OutputStream outputStream, int bufferSize, long size) throws IOException { if(size > 0) { int readBytes = 0; long count = size; int length = Math.min(bufferSize, (int)(size)); byte[] buffer = new byte[length]; while(count > 0) { if(count > length) { readBytes = inputStream.read(buffer, 0, length); } else { readBytes = inputStream.read(buffer, 0, (int)count); } if(readBytes > 0) { outputStream.write(buffer, 0, readBytes); count -= readBytes; } else { break; } } outputStream.flush(); } } } | |
![]() | ![]() |