com.jianggujin.http.core.JRequestExecuter Maven / Gradle / Ivy
The newest version!
/**
* Copyright 2018 jianggujin (www.jianggujin.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jianggujin.http.core;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Map.Entry;
import javax.net.ssl.HttpsURLConnection;
import com.jianggujin.http.request.JRequestBodyResolverFactory;
import com.jianggujin.http.util.JDataUtils;
import com.jianggujin.http.util.JKeyVal;
import com.jianggujin.http.util.JOutputStream;
/**
* 请求执行器
*
* @author jianggujin
*
*/
public final class JRequestExecuter {
private static final String CONTENT_TYPE = "Content-Type";
private static final String MULTIPART_FORM_DATA = "multipart/form-data";
private static final String FORM_URL_ENCODED = "application/x-www-form-urlencoded";
private static JRequestExecuterListener requestExecuterListener = null;
protected static void execute(JRequest req) throws JHttpException {
if (req == null) {
throw new IllegalArgumentException("Request must not be null");
}
String protocol = req.url().getProtocol();
if (!"http".equals(protocol) && !"https".equals(protocol)) {
throw new JHttpException("Only http & https protocols supported");
}
final boolean methodHasBody = req.forceHasBody() || req.method().hasBody();
final boolean hasRequestBody = req.requestBody() != null;
if (!methodHasBody) {
if (hasRequestBody) {
throw new IllegalArgumentException("Cannot set a request body for HTTP method " + req.method());
}
}
String mimeBoundary = null;
if (hasData(req) && (!methodHasBody || hasRequestBody)) {
try {
serialiseRequestUrl(req);
} catch (IOException e) {
throw new JHttpException(e);
}
} else if (methodHasBody) {
mimeBoundary = setOutputContentType(req);
}
HttpURLConnection conn;
try {
conn = createConnection(req);
} catch (IOException e) {
throw new JHttpException(e);
}
try {
if (requestExecuterListener != null) {
requestExecuterListener.beforeConnect(conn, req);
}
conn.connect();
if (conn.getDoOutput()) {
writePost(req, conn.getOutputStream(), mimeBoundary);
}
// 执行一次,内部会调用getInputStream,目的是为了解析响应,如果设置了CookieManager,保证获得Cookie
// Map> headers = conn.getHeaderFields();
InputStream stream = conn.getErrorStream() != null ? conn.getErrorStream() : conn.getInputStream();
JResponse response = req.response();
if (response != null) {
try {
response.onComplete(stream, conn, req);
} finally {
JDataUtils.close(stream);
if (requestExecuterListener != null) {
requestExecuterListener.onComplete(conn, req, response);
}
}
} else if (requestExecuterListener != null) {
requestExecuterListener.onComplete(conn, req, response);
}
} catch (Exception e) {
throw new JHttpException(e);
} finally {
conn.disconnect();
}
}
/***
* 获得请求cookie
*
* @param req
* @return
*/
private static String getRequestCookieString(JRequest req) {
StringBuilder sb = new StringBuilder();
boolean first = true;
for (Entry cookie : req.cookies().entrySet()) {
if (!first)
sb.append("; ");
else
first = false;
sb.append(cookie.getKey()).append('=').append(cookie.getValue() == null ? "" : cookie.getValue());
}
return sb.toString();
}
/**
* 序列化请求地址
*
* @param req
* @throws IOException
*/
private static void serialiseRequestUrl(JRequest req) throws IOException {
URL in = req.url();
StringBuilder url = new StringBuilder();
boolean first = true;
url.append(in.getProtocol()).append("://").append(in.getAuthority()) // 包含主机、端口
.append(in.getPath()).append("?");
if (in.getQuery() != null) {
url.append(in.getQuery());
first = false;
}
if (hasData(req)) {
for (JKeyVal keyVal : req.data()) {
if (keyVal.hasInputStream()) {
throw new IllegalArgumentException("InputStream data not supported in URL query string.");
}
if (!first) {
url.append('&');
} else {
first = false;
}
url.append(keyVal.key()).append('=')
.append(keyVal.value() == null ? "" : URLEncoder.encode(keyVal.value(), req.charset()));
}
req.data().clear();
}
req.url(new URL(url.toString()));
}
/**
* 设置Content-Type
*
* @param req
* @return
*/
private static String setOutputContentType(final JRequest req) {
String bound = null;
if (needsMultipart(req)) {
bound = JDataUtils.mimeBoundary();
req.header(CONTENT_TYPE, MULTIPART_FORM_DATA + "; boundary=" + bound);
} else if (!req.hasHeader(CONTENT_TYPE)) {// 如果没有设置,则设置默认值,否则会被覆盖
req.header(CONTENT_TYPE, FORM_URL_ENCODED + "; charset=" + req.charset());
}
return bound;
}
/**
* 判断是否需要多部分
*
* @param req
* @return
*/
private static boolean needsMultipart(JRequest req) {
boolean needsMulti = false;
if (hasData(req)) {
for (JKeyVal keyVal : req.data()) {
if (keyVal.hasInputStream()) {
needsMulti = true;
break;
}
}
}
return needsMulti;
}
/**
* 创建连接
*
* @param req
* @return
* @throws IOException
*/
private static HttpURLConnection createConnection(JRequest req) throws IOException {
final HttpURLConnection conn = (HttpURLConnection) (req.proxy() == null ? req.url().openConnection()
: req.url().openConnection(req.proxy()));
conn.setRequestMethod(req.method().name());
conn.setInstanceFollowRedirects(true);
conn.setConnectTimeout(req.timeout());
conn.setReadTimeout(req.timeout());
if (conn instanceof HttpsURLConnection) {
JSSLContextFactory sslSocketFactory = req.sslContextFactory();
if (sslSocketFactory != null) {
((HttpsURLConnection) conn).setSSLSocketFactory(sslSocketFactory.getSSLContext().getSocketFactory());
((HttpsURLConnection) conn).setHostnameVerifier(sslSocketFactory.getHostnameVerifier());
}
}
if (req.forceHasBody() || req.method().hasBody()) {
conn.setDoOutput(true);
}
if (req.cookies() != null && req.cookies().size() > 0) {
conn.addRequestProperty("Cookie", getRequestCookieString(req));
}
if (req.headers() != null && req.headers().size() > 0) {
for (Entry header : req.headers().entrySet()) {
conn.setRequestProperty(header.getKey(), header.getValue() == null ? "" : header.getValue());
}
}
return conn;
}
/**
* 写POST数据
*
* @param req
* @param outputStream
* @param bound
* @throws IOException
*/
private static void writePost(final JRequest req, final OutputStream outputStream, final String bound)
throws IOException {
// final List data = req.data();
final JOutputStream stream = new JOutputStream(outputStream, req.charset());
try {
if (bound != null) {
// boundary will be set if we're in multipart mode
if (hasData(req)) {
for (JKeyVal keyVal : req.data()) {
stream.write("--");
stream.write(bound);
stream.write("\r\n");
stream.write("Content-Disposition: form-data; name=\"");
stream.write(JDataUtils.encodeMimeName(keyVal.key()));
// %22
stream.write("\"");
if (keyVal.hasInputStream()) {
stream.write("; filename=\"");
stream.write(JDataUtils.encodeMimeName(keyVal.value()));
stream.write("\"\r\nContent-Type: application/octet-stream\r\n\r\n");
stream.flush(); // flush
JDataUtils.crossStreams(keyVal.inputStream(), outputStream);
JDataUtils.close(keyVal.inputStream());
outputStream.flush();
} else {
stream.write("\r\n\r\n");
stream.write(keyVal.value() == null ? "" : keyVal.value());
}
stream.write("\r\n");
}
}
stream.write("--");
stream.write(bound);
stream.write("--");
} else if (req.requestBody() != null) {
JRequestBodyResolver resolver = req.requestBodyResolver();
if (resolver == null) {
Class> clazz = req.requestBody().getClass();
resolver = JRequestBodyResolverFactory.getFirstSupportResolver(clazz);
}
if (resolver == null) {
throw new IllegalArgumentException("not found RequestBodyResolver");
}
resolver.write(req, req.requestBody(), stream);
} else {
if (hasData(req)) {
// regular form data (application/x-www-form-urlencoded)
boolean first = true;
for (JKeyVal keyVal : req.data()) {
if (!first) {
stream.write("&");
} else {
first = false;
}
stream.write(keyVal.key());
stream.write("=");
stream.write(keyVal.value() == null ? "" : URLEncoder.encode(keyVal.value(), req.charset()));
}
}
}
stream.flush();
} catch (IOException e) {
throw e;
} finally {
stream.close();
}
}
/**
* 设置请求监听
*
* @param listener
*/
public static void setRequestExecuterListener(JRequestExecuterListener listener) {
JRequestExecuter.requestExecuterListener = listener;
}
/**
* 开启调试
*
* @param debug
*/
public static void enableDebug(boolean debug) {
System.setProperty("javax.net.debug", debug ? "all" : null);
}
/**
* 判断是否有数据
*
* @param req
* @return
*/
private static boolean hasData(JRequest req) {
return req.data() != null && req.data().size() > 0;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy