您的位置:首页 > 理论基础 > 计算机网络

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

2017-12-02 17:24 381 查看
使用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);
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: