package org.nutz.http; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.InetSocketAddress; import java.net.Proxy; import java.net.URL; import java.net.URLEncoder; import java.security.SecureRandom; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.HashMap; import java.util.Map; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import org.nutz.Nutz; import org.nutz.http.Request.METHOD; import org.nutz.http.sender.FilePostSender; import org.nutz.lang.Encoding; import org.nutz.lang.Lang; import org.nutz.lang.Strings; public class Http { /** * @see https://en.wikipedia.org/wiki/List_of_HTTP_status_codes */ private static final Map<String, String> code_text = new HashMap<String, String>(); static { code_text.put("100", "Continue"); code_text.put("101", "Switching Protocols"); code_text.put("102", "Processing"); code_text.put("200", "OK"); code_text.put("201", "Created"); code_text.put("202", "Accepted"); code_text.put("203", "Non-Authoritative Information"); // (since HTTP/1.1) code_text.put("204", "No Content"); code_text.put("205", "Reset Content"); code_text.put("206", "Partial Content"); code_text.put("207", "Multi-Status"); code_text.put("208", "Already Reported"); code_text.put("226", "IM Used"); code_text.put("301", "Moved Permanently"); code_text.put("302", "Found"); code_text.put("303", "See Other"); // (since HTTP/1.1) code_text.put("304", "Not Modified "); code_text.put("305", "Use Proxy"); // (since HTTP/1.1) code_text.put("306", "Switch Proxy"); code_text.put("307", "Temporary Redirect"); // (since HTTP/1.1) code_text.put("308", "Permanent Redirect"); code_text.put("400", "Bad Request"); code_text.put("401", "Unauthorized"); code_text.put("402", "Payment Required"); code_text.put("403", "Forbidden"); code_text.put("404", "Not Found"); code_text.put("405", "Method Not Allowed"); code_text.put("406", "Not Acceptable"); code_text.put("407", "Proxy Authentication Required "); code_text.put("408", "Request Timeout"); code_text.put("409", "Conflict"); code_text.put("410", "Gone"); code_text.put("411", "Length Required"); code_text.put("412", "Precondition Failed"); code_text.put("413", "Payload Too Large"); code_text.put("414", "URI Too Long"); code_text.put("415", "Unsupported Media Type"); code_text.put("416", "Range Not Satisfiable"); code_text.put("417", "Expectation Failed"); // ... 后面的 "4xx" 都是什么鬼 -_-! 先不抄了吧 code_text.put("500", "Internal Server Error"); code_text.put("501", "Not Implemented"); code_text.put("502", "Bad Gateway"); code_text.put("503", "Service Unavailable"); code_text.put("504", "Gateway Timeout"); code_text.put("505", "HTTP Version Not Supported"); code_text.put("506", "Variant Also Negotiates"); code_text.put("507", "Insufficient Storage "); code_text.put("508", "Loop Detected"); code_text.put("509", "Bandwidth Limit Exceeded "); code_text.put("510", "Not Extended "); code_text.put("511", "Network Authentication Required"); code_text.put("520", "Unknown Error"); code_text.put("522", "Origin Connection Time-out"); code_text.put("598", "Network read timeout error "); code_text.put("599", "Network connect timeout error"); } public static String getStatusText(int statusCode) { return code_text.get(""+statusCode); } public static String getStatusText(int statusCode, String dft) { return Strings.sNull(code_text.get(""+statusCode), dft); } public static class multipart { public static String getBoundary(String contentType) { if (null == contentType) return null; for (String tmp : contentType.split(";")) { tmp = tmp.trim(); if (tmp.startsWith("boundary=")) { return tmp.substring("boundary=".length()); } } return null; } public static String formatName(String name, String filename, String contentType) { StringBuilder sb = new StringBuilder(); sb.append("Content-Disposition: form-data; name=\""); sb.append(name); sb.append("\""); if (null != filename) sb.append("; filename=\"" + filename + "\""); if (null != contentType) sb.append("\nContent-Type: " + contentType); sb.append('\n' + '\n'); return sb.toString(); } public static String formatName(String name) { return formatName(name, null, null); } } /** * 访问一个URL * * @param url * 需要访问的URL * @return http响应 */ public static Response get(String url) { return Sender.create(Request.get(url)).send(); } /** * 访问一个URL,并设置超时 * * @param url * 需要访问的URL * @param timeout * 超时设置,单位为毫秒 * @return http响应 */ public static Response get(String url, int timeout) { return Sender.create(Request.get(url)).setTimeout(timeout).send(); } public static Response get(String url, Map<String, Object> params, int timeout) { return Sender.create(Request.get(url).setParams(params)).setTimeout(timeout).send(); } public static Response get(String url, Header header, int timeout) { return Sender.create(Request.get(url).setHeader(header)).setTimeout(timeout).send(); } /** * 访问一个URL,并设置超时及参数 * * @param url * 需要访问的URL * @param params * 参数 * @param timeout * 超时设置,单位为毫秒 * @return http响应 */ public static String post(String url, Map<String, Object> params, int timeout) { return Sender.create(Request.create(url, METHOD.POST, params, null)) .setTimeout(timeout) .send() .getContent(); } /** * 访问一个URL,并设置超时及参数 * * @param url * 需要访问的URL * @param params * 参数 * @param timeout * 超时设置,单位为毫秒 * @return http响应 */ public static Response post2(String url, Map<String, Object> params, int timeout) { return Sender.create(Request.create(url, METHOD.POST, params, null)) .setTimeout(timeout) .send(); } public static Response post3(String url, Object body, Header header, int timeout) { Request req = Request.create(url, METHOD.POST).setHeader(header); if (body != null) { if (body instanceof InputStream) { req.setInputStream((InputStream) body); } else if (body instanceof byte[]) { req.setData((byte[]) body); } else { req.setData(String.valueOf(body)); } } return Sender.create(req).setTimeout(timeout).send(); } public static Response upload(String url, Map<String, Object> params, Header header, int timeout) { Request req = Request.create(url, METHOD.POST, params, header); return new FilePostSender(req).setTimeout(timeout).send(); } public static String encode(Object s) { return encode(s, null); } public static String encode(Object s, String enc) { if (null == s) return ""; try { // Fix issue 283, 按照“茶几”的意见再次修改 return URLEncoder.encode(s.toString(), enc == null ? Encoding.CHARSET_UTF8.name() : enc); } catch (UnsupportedEncodingException e) { throw Lang.wrapThrow(e); } } public static String post(String url, Map<String, Object> params, String inenc, String reenc) { return Sender.create(Request.create(url, METHOD.POST, params, null).setEnc(inenc)) .send() .getContent(reenc); } public static Response postXML(String url, String xml, int timeout) { Request req = Request.create(url, METHOD.POST); req.setData(xml); req.getHeader().set("Content-Type", "application/xml"); return Sender.create(req).setTimeout(timeout).send(); } protected static ProxySwitcher proxySwitcher; protected static boolean autoSwitch; public static void setAutoSwitch(boolean use) { autoSwitch = use; } public static void setHttpProxy(String host, int port) { final Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port)); proxySwitcher = new ProxySwitcher() { public Proxy getProxy(URL url) { return proxy; } public Proxy getProxy(Request req) { if ("close".equals(req.getHeader().get("NoProxy"))) return null; String url = req.getUrl().toString(); if (url.startsWith("http") && url.contains("://") && url.length() > "https://".length()) { url = url.substring(url.indexOf("://") + "://".length()); if (url.startsWith("127.0.0") || url.startsWith("localhost")) return null; } req.getHeader().set("Connection", "close"); return getProxy(req.getUrl()); } }; } /* * please use setSocketProxy method */ @Deprecated public static void setSocktProxy(String host, int port) { final Proxy proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(host, port)); proxySwitcher = new ProxySwitcher() { public Proxy getProxy(URL url) { return proxy; } public Proxy getProxy(Request req) { if ("close".equals(req.getHeader().get("NoProxy"))) return null; String url = req.getUrl().toString(); if (url.startsWith("http") && url.contains("://") && url.length() > "https://".length()) { url = url.substring(url.indexOf("://")); if (url.startsWith("127.0.0") || url.startsWith("localhost")) return null; } req.getHeader().set("Connection", "close"); return getProxy(req.getUrl()); } }; } public static void setSocketProxy(String host, int port) { final Proxy proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress(host, port)); proxySwitcher = new ProxySwitcher() { public Proxy getProxy(URL url) { return proxy; } public Proxy getProxy(Request req) { if ("close".equals(req.getHeader().get("NoProxy"))) return null; String url = req.getUrl().toString(); if (url.startsWith("http") && url.contains("://") && url.length() > "https://".length()) { url = url.substring(url.indexOf("://")); if (url.startsWith("127.0.0") || url.startsWith("localhost")) return null; } req.getHeader().set("Connection", "close"); return getProxy(req.getUrl()); } }; } public static ProxySwitcher getProxySwitcher() { return proxySwitcher; } public static void setProxySwitcher(ProxySwitcher proxySwitcher) { Http.proxySwitcher = proxySwitcher; } protected static SSLSocketFactory sslSocketFactory; /** * 禁用JVM的https证书验证机制, 例如访问12306, 360 openapi之类的自签名证书 * * @return 禁用成功与否 */ public static boolean disableJvmHttpsCheck() { try { setSSLSocketFactory(nopSSLSocketFactory()); } catch (Exception e) { return false; } return true; } public static SSLSocketFactory nopSSLSocketFactory() throws Exception { SSLContext sc = SSLContext.getInstance("SSL"); TrustManager[] tmArr = {new X509TrustManager() { public void checkClientTrusted(X509Certificate[] paramArrayOfX509Certificate, String paramString) throws CertificateException {} public void checkServerTrusted(X509Certificate[] paramArrayOfX509Certificate, String paramString) throws CertificateException {} public X509Certificate[] getAcceptedIssuers() { return null; } }}; sc.init(null, tmArr, new SecureRandom()); return sc.getSocketFactory(); } public static void setSSLSocketFactory(SSLSocketFactory sslSocketFactory) { Http.sslSocketFactory = sslSocketFactory; } public static HashMap<String, String> DEFAULT_HEADERS = new HashMap<String, String>(); static { DEFAULT_HEADERS.put("User-Agent", "Nutz.Robot " + Nutz.version()); DEFAULT_HEADERS.put("Accept-Encoding", "gzip,deflate"); DEFAULT_HEADERS.put("Accept", "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"); DEFAULT_HEADERS.put("Accept-Language", "en-US,en,zh,zh-CN"); DEFAULT_HEADERS.put("Accept-Charset", "ISO-8859-1,*,utf-8"); DEFAULT_HEADERS.put("Connection", "keep-alive"); DEFAULT_HEADERS.put("Cache-Control", "max-age=0"); } }