Jfinal HttpKit.post(url,data)源码解析

来源:互联网 发布:windows 空间音效 编辑:程序博客网 时间:2024/06/06 17:34

使用Jfinal来测试一个接口非常方便,只需要发送一个post请求即可。最近跟踪源码,终于知道底层封装是怎么走的。

首先:
使用实例:

String result = HttpKit.post(url, "{'api': 'uac','action': 'getAccounts'}");

第一个参数是请求地址,第二个参数是拼装的json串。

先调用带四个参数的post方法。

public static String post(String url, String data) {        return post(url, null, data, null);    }
/**     * Send POST request     */    public static String post(String url, Map<String, String> queryParas, String data, Map<String, String> headers) {    /**使用的是JDK自带的java.net.HttpURLConnection**/        HttpURLConnection conn = null;        try {        /**根据请求地址url和查询参数queryParas和请求头headers得到连接信息**/            conn = getHttpConnection(buildUrlWithQueryString(url, queryParas), POST, headers);            /**建立连接**/            conn.connect();            OutputStream out = conn.getOutputStream();            out.write(data != null ? data.getBytes(CHARSET) : null);            out.flush();            out.close();            /**根据连接返回响应字符串**/            return readResponseString(conn);        }        catch (Exception e) {            throw new RuntimeException(e);        }        finally {        /**关闭连接,也就是说发送一次post请求,连接用完之后会直接关闭**/            if (conn != null) {                conn.disconnect();            }        }    }

buildUrlWithQueryString方法主要是根据url和查询参数构建真实的访问url
http://ip:port/urlPath?username=admin&password=123456

/**     * Build queryString of the url     */    private static String buildUrlWithQueryString(String url, Map<String, String> queryParas) {    /**如果没有参数,直接返回url**/        if (queryParas == null || queryParas.isEmpty())            return url;        StringBuilder sb = new StringBuilder(url);        boolean isFirst;        /**如果url地址本身没有?,就直接拼接一个?**/        if (!url.contains("?")) {            isFirst = true;            sb.append("?");        }        else {            isFirst = false;        }        /**遍历queryParas Map**/        for (Entry<String, String> entry : queryParas.entrySet()) {            /**如果有?就直接拼接key=value,否则在原来的基础上&key=value**/            if (isFirst) isFirst = false;               else sb.append("&");            String key = entry.getKey();            String value = entry.getValue();            if (StrKit.notBlank(value))            /**对value进行转码,防止特殊字符之类的,CHARSET是默认的UTF-8,可以通过发送Post之前调用下HttpKit.setCharSet(String charSet)方法**/                try {value = URLEncoder.encode(value, CHARSET);} catch (UnsupportedEncodingException e) {throw new RuntimeException(e);}            sb.append(key).append("=").append(value);        }        return sb.toString();    }

以下是设置默认的CHARSET编码

/**成员遍历,非final修饰**/private static String CHARSET = "UTF-8";public static void setCharSet(String charSet) {        if (StrKit.isBlank(charSet)) {            throw new IllegalArgumentException("charSet can not be blank.");        }        HttpKit.CHARSET = charSet;    }

成功拼接好了请求访问地址,接下来就是根据url,使用post方法,以及头部信息headers得到HttpURLConnection。

private static HttpURLConnection getHttpConnection(String url, String method, Map<String, String> headers) throws IOException, NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException {        /**看到没,jfinal就是封装而已,没有其他,用的是JDK自带的java.net.URL**/        URL _url = new URL(url);        HttpURLConnection conn = (HttpURLConnection)_url.openConnection();        /**对Https的支持**/        if (conn instanceof HttpsURLConnection) {/**sslSocketFactory的值见后面的initSSLSocketFactory**/        ((HttpsURLConnection)conn).setSSLSocketFactory(sslSocketFactory);            ((HttpsURLConnection)conn).setHostnameVerifier(trustAnyHostnameVerifier);        }        conn.setRequestMethod(method);        conn.setDoOutput(true);        conn.setDoInput(true);        /**设置了默认连接超时时间19秒**/        conn.setConnectTimeout(19000);        /**设置读超时时间19秒**/        conn.setReadTimeout(19000);        conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded");        conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36");        if (headers != null && !headers.isEmpty())            for (Entry<String, String> entry : headers.entrySet())                conn.setRequestProperty(entry.getKey(), entry.getValue());        return conn;    }

Https的SocketFactory工厂的初始化。

private static final SSLSocketFactory sslSocketFactory = initSSLSocketFactory();    private static final TrustAnyHostnameVerifier trustAnyHostnameVerifier = new HttpKit().new TrustAnyHostnameVerifier();    private static SSLSocketFactory initSSLSocketFactory() {        try {        /**内部类实现了 javax.net.ssl.X509TrustManager**/            TrustManager[] tm = {new HttpKit().new TrustAnyTrustManager() };            SSLContext sslContext = SSLContext.getInstance("TLS");  // ("TLS", "SunJSSE");            sslContext.init(null, tm, new java.security.SecureRandom());            return sslContext.getSocketFactory();        }        catch (Exception e) {            throw new RuntimeException(e);        }    }

都是采用默认的实现

private class TrustAnyHostnameVerifier implements HostnameVerifier {        public boolean verify(String hostname, SSLSession session) {            return true;        }    }    private class TrustAnyTrustManager implements X509TrustManager {        public X509Certificate[] getAcceptedIssuers() {            return null;          }        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {        }        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {        }    }

根据连接输出结果,比较简单,就是文件流的读取和写入

private static String readResponseString(HttpURLConnection conn) {        StringBuilder sb = new StringBuilder();        InputStream inputStream = null;        try {            inputStream = conn.getInputStream();            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, CHARSET));            String line = null;            while ((line = reader.readLine()) != null){                sb.append(line).append("\n");            }            return sb.toString();        }        catch (Exception e) {            throw new RuntimeException(e);        }        finally {            if (inputStream != null) {                try {                    inputStream.close();                } catch (IOException e) {                    LogKit.error(e.getMessage(), e);                }            }        }    }
原创粉丝点击