package com.smtservlet.util; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpCookie; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class SMTHttpClient { public abstract static class SMTHttpClientStream { public void ready(HttpURLConnection conn) throws Exception{} public void post(HttpURLConnection conn, OutputStream os) throws Exception{} public void receive(HttpURLConnection conn, InputStream is) throws Exception{} } public static class SMTHttpClientPostFile { public String _name; public String _fileName; public InputStream _is; public SMTHttpClientPostFile(String name, String fileName, InputStream is) { _name = name; _fileName = fileName; _is = is; } } protected static class SMTHttpClientCookieManager { protected static Logger _logger = LogManager.getLogger(SMTHttpClientCookieManager.class); protected Object _lock = new Object(); protected Map> _mapHost2Cookie = new HashMap>(); protected String getUrlHost(URL uri) { return String.format("%s://%s:%d", uri.getProtocol(), uri.getHost(), uri.getPort()); } public Map getCookieByURL(URL url) { return _mapHost2Cookie.get(getUrlHost(url)); } public void setCookie(URL url, String[] cookies) { String uriHost = getUrlHost(url); Map mapCookies = _mapHost2Cookie.get(uriHost); if(mapCookies == null) { mapCookies = new HashMap(); _mapHost2Cookie.put(uriHost, mapCookies); } for(int i = 0; i < cookies.length; i += 2) { HttpCookie cookie = new HttpCookie(cookies[i + 0], cookies[i + 1]); cookie.setPath(url.getPath()); mapCookies.put(cookie.getName(), cookie); } } public void get(HttpURLConnection conn) { synchronized(_lock) { URL uri = conn.getURL(); String uriHost = getUrlHost(uri); Map mapCookies = _mapHost2Cookie.get(uriHost); if(mapCookies == null) return; StringBuilder sbCookie = new StringBuilder(); for(Entry entry : mapCookies.entrySet()) { HttpCookie cookie = entry.getValue(); if(!uri.getPath().startsWith(cookie.getPath()) || cookie.hasExpired()) continue; if(sbCookie.length() > 0) sbCookie.append(";"); sbCookie.append(String.format("%s=%s", cookie.getName(), cookie.getValue())); //sbCookie.append(cookie.toString()); } if(sbCookie.length() > 0) { //_logger.log(SMTLog.Debug, String.format("Get Cookie:%s=%s", uri.toString(), sbCookie.toString())); conn.setRequestProperty("Cookie", sbCookie.toString()); } } } public void put(HttpURLConnection conn) { synchronized(_lock) { URL uri = conn.getURL(); List headers = null; for(Entry> entry : conn.getHeaderFields().entrySet()) { String key = entry.getKey(); if(key != null && key.equalsIgnoreCase("set-cookie")) { headers = entry.getValue(); break; } } if(headers == null) return; String uriHost = getUrlHost(uri); Map mapCookies = _mapHost2Cookie.get(uriHost); if(mapCookies == null) { mapCookies = new HashMap(); _mapHost2Cookie.put(uriHost, mapCookies); } for(String header : headers) { for(HttpCookie cookie : HttpCookie.parse(header)) { mapCookies.put(cookie.getName(), cookie); //_logger.log(SMTLog.Debug, String.format("Set Cookie:%s=%s", uri.toString(), header)); } } mapCookies = null; } } } protected boolean _logHead = true; protected String _encodeName = "UTF-8"; protected static Logger _logger = LogManager.getLogger(SMTHttpClient.class); protected SMTHttpClientCookieManager _cookieManager = new SMTHttpClientCookieManager(); public SMTHttpClient() { _cookieManager = new SMTHttpClientCookieManager(); } public String getEncodeName() { return _encodeName; } public void setEncodeName(String encodeName) { _encodeName = encodeName; } public void setCookies(String surl, String[] cookies) throws Exception { URL url = new URL(surl); _cookieManager.setCookie(url, cookies); } public Map getCookies(String surl) throws Exception { URL url = new URL(surl); return _cookieManager.getCookieByURL(url); } /** * 用GET方式请求url,并返回字节流 * * @param url - 请求的url * @param params - 请求的参数列表(名称,值) * @param heads - 请求头的设置(名称,值) * @param out - 返回的输出流 * @throws Exception */ public void getHttpStream(String url, String[] params, String[] heads, final OutputStream out) throws Exception { StringBuilder sbParams = new StringBuilder(); sbParams.append(url); if(params != null && params.length > 0) { sbParams.append("?"); for(int i = 0; i < params.length; i += 2) { if(sbParams.length() > 0) sbParams.append("&"); sbParams.append(params[i + 0]); sbParams.append("="); sbParams.append(URLEncoder.encode(params[i + 1], _encodeName)); } } queryHttpClient("GET", url, new SMTHttpClientStream(){ @Override public void receive(HttpURLConnection conn, InputStream is) throws Exception{ int size; byte[] data = new byte[10240]; while((size = is.read(data)) > 0) { out.write(data, 0, size); } } }, heads); } /** * 用GET方式请求url,并返回字符串 * * @param url - 请求的url * @param params - 请求的参数列表(名称,值) * @param heads - 请求头的设置(名称,值) * @return - 返回请求的字符串 * @throws Exception */ public String getHttpString(String url, String[] params, String[] heads) throws Exception { return new String(getHttpBytes(url, params, heads), this._encodeName); } public byte[] getHttpBytes(String url, String[] params, String[] heads) throws Exception { StringBuilder sbParams = new StringBuilder(); sbParams.append(url); if(params != null && params.length > 0) { sbParams.append("?"); for(int i = 0; i < params.length; i += 2) { if(sbParams.length() > 0) sbParams.append("&"); sbParams.append(params[i + 0]); sbParams.append("="); sbParams.append(URLEncoder.encode(params[i + 1], _encodeName)); } } final ByteArrayOutputStream bos = new ByteArrayOutputStream(); queryHttpClient("GET", sbParams.toString(), new SMTHttpClientStream(){ @Override public void receive(HttpURLConnection conn, InputStream is) throws Exception{ int size; byte[] data = new byte[10240]; while((size = is.read(data)) > 0) { bos.write(data, 0, size); } } }, heads); return bos.toByteArray(); } /** * 用POST方式上传文件,并返回字符串 * * @param url - 请求的url * @param params - 请求的参数列表(名称,值) * @param heads - 请求头的设置(名称,值) * @param files - 要上传的文件列表 * @return - 返回请求的字符串 * @throws Exception */ public String postStreamHttp(String url, final String[] params, String[] heads, final SMTHttpClientPostFile[] files) throws Exception { final ByteArrayOutputStream bos = new ByteArrayOutputStream(); final String BOUNDARY = "---------------------------" + SMTStatic.newUUID(); queryHttpClient("POST", url, new SMTHttpClientStream(){ @Override public void ready(HttpURLConnection conn) throws Exception{ conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY.substring(2)); } @Override public void post(HttpURLConnection conn, OutputStream os) throws Exception{ // 上传参数 if(params != null && params.length > 0) { for(int i = 0; i < params.length; i += 2) { String data = String.format( "%s\r\n" + // BOUNDARY "Content-Disposition: form-data; name=\"%s\"\r\n" + // name "\r\n" + "%s\r\n", // value BOUNDARY, params[i + 0], URLEncoder.encode(params[i + 1], _encodeName) ); os.write(data.getBytes(_encodeName)); } } // 上传文件 if(files != null && files.length > 0) { for(int i = 0; i < files.length; i ++) { // 发送文件提交头信息 String data = String.format( "%s\r\n" + // BOUNDARY "Content-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\n" + // name filename "Content-Type: application/octet-stream\r\n" + "\r\n", BOUNDARY, files[i]._name, files[i]._fileName ); os.write(data.getBytes(_encodeName)); // 发送文件内容 int size; byte[] data1 = new byte[10240]; while((size = files[i]._is.read(data1)) > 0) { os.write(data1, 0, size); } // 写入换行符 os.write("\r\n".getBytes(_encodeName)); } // 写入结束节 os.write(String.format("%s--", BOUNDARY).getBytes(_encodeName)); } } @Override public void receive(HttpURLConnection conn, InputStream is) throws Exception{ int size; byte[] data = new byte[10240]; while((size = is.read(data)) > 0) { bos.write(data, 0, size); } } }, heads); String ret = new String(bos.toByteArray(), _encodeName); return ret; } /** * 用POST方式请求,并返回字符串 * * @param url - 请求的url * @param params - 请求的参数列表(名称,值) * @param heads - 请求头的设置(名称,值) * @return - 返回请求的字符串 * @throws Exception */ public String postHttpString(String url, String[] params, String[] heads) throws Exception { return new String(postHttpBytes(url, params, heads), _encodeName); } public byte[] postHttpBytes(String url, String[] params, String[] heads) throws Exception { final StringBuilder sbParams = new StringBuilder(); if(params != null) { for(int i = 0; i < params.length; i += 2) { if(sbParams.length() > 0) sbParams.append("&"); sbParams.append(params[i + 0]); sbParams.append("="); sbParams.append(URLEncoder.encode(params[i + 1], _encodeName)); } } final ByteArrayOutputStream bos = new ByteArrayOutputStream(); queryHttpClient("POST", url, new SMTHttpClientStream(){ @Override public void post(HttpURLConnection conn, OutputStream os) throws Exception{ os.write(sbParams.toString().getBytes(_encodeName)); } @Override public void receive(HttpURLConnection conn, InputStream is) throws Exception{ int size; byte[] data = new byte[10240]; while((size = is.read(data)) > 0) { bos.write(data, 0, size); } } },heads); return bos.toByteArray(); } public Json postHttpBodyToJson(String url, String body, String[] heads) throws Exception { final ByteArrayOutputStream bos = new ByteArrayOutputStream(); queryHttpClient("POST", url, new SMTHttpClientStream(){ @Override public void post(HttpURLConnection conn, OutputStream os) throws Exception{ os.write(body.toString().getBytes(_encodeName)); } @Override public void receive(HttpURLConnection conn, InputStream is) throws Exception{ int size; byte[] data = new byte[10240]; while((size = is.read(data)) > 0) { bos.write(data, 0, size); } } },heads); return Json.read(new String(bos.toByteArray(), _encodeName)); } public String postHttpBodyToString(String url, String body, String[] heads) throws Exception { final ByteArrayOutputStream bos = new ByteArrayOutputStream(); queryHttpClient("POST", url, new SMTHttpClientStream(){ @Override public void post(HttpURLConnection conn, OutputStream os) throws Exception{ os.write(body.toString().getBytes(_encodeName)); } @Override public void receive(HttpURLConnection conn, InputStream is) throws Exception{ int size; byte[] data = new byte[10240]; while((size = is.read(data)) > 0) { bos.write(data, 0, size); } } },heads); return new String(bos.toByteArray(), _encodeName); } public void queryHttpClient(String method, String surl, SMTHttpClientStream notify, String[] mapHeads)throws Exception { HttpURLConnection connection = null; InputStream inputStream = null; OutputStream outputStream = null; try { // 创建连接 URL url = new URL(surl); connection = (HttpURLConnection) url.openConnection(); // 针对GET的操作 if("GET".equalsIgnoreCase(method)) { // 设置cookie _cookieManager.get(connection); // 如果存在head映射表,则将其注入 if(mapHeads != null) { for(int i = 0; i < mapHeads.length; i += 2) { connection.setRequestProperty(mapHeads[i + 0], mapHeads[i + 1]); } } // 通过通知方式设定标题 if(notify != null) notify.ready(connection); connection.connect(); // 获取新的cookie _cookieManager.put(connection); } // 针对POST的操作 else if("POST".equalsIgnoreCase(method)) { // 将HTTP头发送过去 //_cookieManager.put(new URI(surl), connection.getHeaderFields()); connection.setDoOutput(true); connection.setRequestMethod("POST"); connection.setUseCaches(false); connection.setInstanceFollowRedirects(false); //connection.setRequestProperty("Content-Type", request.getHeader("Content-Type")); //connection.setRequestProperty("Content-Length", request.getHeader("Content-Length")); connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + _encodeName); //connection.setRequestProperty("Content-Length", request.getHeader("Content-Length")); // 设置cookie _cookieManager.get(connection); // 如果存在head映射表,则将其注入 if(mapHeads != null) { for(int i = 0; i < mapHeads.length; i += 2) { connection.setRequestProperty(mapHeads[i + 0], mapHeads[i + 1]); } } // 通过通知方式设定标题 if(notify != null) notify.ready(connection); connection.connect(); // 将POST的信息复制到转发服务器中 outputStream = connection.getOutputStream(); // 通过通知方式上传参数 if(notify != null) notify.post(connection, outputStream); // 获取新的cookie _cookieManager.put(connection); // 关闭参数传递通道 outputStream.flush(); outputStream.close(); outputStream = null; } else throw new RuntimeException(String.format("unsupport method %s", method)); // 打开远程流读取远程信息 inputStream = connection.getInputStream(); if(notify != null) notify.receive(connection, inputStream); } finally { if(inputStream != null)inputStream.close(); if(outputStream != null)outputStream.close(); if(connection != null)connection.disconnect(); } } }