package li.http;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.net.HttpCookie;
import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
/**
* HTTP请求
*
* @author 明伟
*/
public class Request {
public static final String GET = "GET", POST = "POST", UTF8 = "UTF-8", FORM_URLENCODED = "application/x-www-form-urlencoded";
private String url = "", urlWithParameters, method = GET;
private Map<String, List<String>> parameters = new HashMap<String, List<String>>();
private Map<String, List<Object>> fields = new HashMap<String, List<Object>>();
private Map<String, List<String>> headers = new HashMap<String, List<String>>();
private Integer connectTimeout = Integer.parseInt(System.getProperty("sun.net.client.defaultConnectTimeout", (5 * 60 * 1000) + ""));// 默认五分钟连接超时
private Integer readTimeout = Integer.parseInt(System.getProperty("sun.net.client.defaultReadTimeout", (5 * 60 * 1000) + ""));// 默认五分钟读取超时
private Boolean followRedirects = HttpURLConnection.getFollowRedirects();// 默认自动跳转30x
private Proxy proxy = Proxy.NO_PROXY;// 默认无代理
/**
* 设置请求地址
*/
public Request setUrl(String url) {
this.url = url;
return this;
}
/**
* GET POST
*/
public Request setMethod(String method) {
this.method = method;
return this;
}
public Map<String, List<String>> getHeaders() {
return this.headers;
}
/**
* 获取单个Header的值
*/
public String getHeader(String key) {
List<String> header = this.headers.get(key);
return null == header ? null : header.get(0);
}
public Request setHeader(String key, String value) {
this.headers.put(key, Arrays.asList(value));
return this;
}
public Request setReferer(String referer) {
this.setHeader("Referer", referer);
return this;
}
public Request setUserAgent(String userAgent) {
this.setHeader("User-Agent", userAgent);
return this;
}
public Request setContentType(String contentType) {
this.setHeader("Content-Type", contentType);
return this;
}
/**
* 是否跳转30x 可通过 HttpURLConnection.setFollowRedirects(true)进行全局设置
*/
public Request setFollowRedirects(Boolean followRedirects) {
this.followRedirects = followRedirects;
return this;
}
/**
* 设置代理 可通过 System.setProperty("http.proxyHost", "208.110.94.187"); System.setProperty("http.proxyPort", "8089"); Authenticator.setDefault(authenticator); 进行全局设置
*/
public Request setProxy(Proxy proxy) {
this.proxy = null == proxy ? Proxy.NO_PROXY : proxy;
return this;
}
/**
* 链接超时,单位毫秒,默认 5 * 60 * 1000 五分钟 可通过 System.setProperty("sun.net.client.defaultConnectTimeout", 1000)进行全局设置
*/
public Request setConnectTimeout(Integer connectTimeout) {
this.connectTimeout = connectTimeout;
return this;
}
/**
* 读取超时,单位毫秒,默认 5 * 60 * 1000 五分钟 可通过 System.setProperty("sun.net.client.defaultReadTimeout", 1000)进行全局设置
*/
public Request setReadTimeout(Integer readTimeout) {
this.readTimeout = readTimeout;
return this;
}
/**
* 设置Cookie
*/
public Request setCookies(List<HttpCookie> cookies) {
this.setCookies(Util.cookieToString(cookies));
return this;
}
/**
* 通过字符串设置Cookies
*/
public Request setCookies(String cookies) {
this.setHeader("Cookie", cookies);
return this;
}
/**
* 通过字符串添加Cookies
*/
public Request addCookies(String cookies) {
cookies = cookies + (null == this.getCookies() ? "" : ("; " + this.getCookies()));
this.setHeader("Cookie", cookies);
return this;
}
/**
* 返回字符串的RequestCookie
*/
public String getCookies() {
return this.getHeader("Cookie");
}
/**
* 返回一个Cookie值
*/
public String getCookie(String key) {
return CookieStore.getCookie(this.getCookies(), key);
}
/**
* 设置GET访问的参数,会添加到url,url中不应当已经存在
*/
public Request setParameters(Map<Object, Object> map) {
for (Entry<Object, Object> entry : map.entrySet()) {
Object value = entry.getValue();
if (!(value instanceof List)) {
value = Arrays.asList(value);
}
this.parameters.put(entry.getKey() + "", (List<String>) value);
}
return this;
}
/**
* 如果有同名项,会被替换
*/
public Request setParameter(String key, Object value) {
if (value instanceof List) {
this.parameters.put(key, (List) value);
} else {
List<String> para = new ArrayList<String>();
para.add(value + "");
this.parameters.put(key, para);
}
return this;
}
/**
* 添加,不替换重名项
*/
public Request addParameter(String key, Object value) {
List<String> parameter = this.parameters.get(key);
if (null == parameter) {
this.setParameter(key, value);
} else {
parameter.add(value + "");
}
return this;
}
/**
* 设置POST请求的表单域
*/
public Request setFields(Map<String, Object> fields) {
this.setMethod(POST);
for (Entry<String, Object> entry : fields.entrySet()) {
Object value = entry.getValue();
if (!(value instanceof List)) {
value = Arrays.asList(value);
}
this.fields.put(entry.getKey(), (List<Object>) value);
}
return this;
}
/**
* 会替换同名项
*/
public Request setField(String key, Object value) {
this.setMethod(POST);
if (value instanceof List) {
this.fields.put(key, (List) value);
} else {
List<Object> para = new ArrayList<Object>();
para.add(value);
this.fields.put(key, para);
}
return this;
}
/**
* 添加,不会替换重名项
*/
public Request addField(String key, Object value) {
this.setMethod(POST);
List<Object> field = this.fields.get(key);
if (null == field) {
this.setField(key, value);
} else {
field.add(value);
}
return this;
}
/**
* 执行HTTP请求,返回Response
*
* @see li.http.Request#execute(Response)
*/
public Response execute() {
return this.execute(new Response());
}
/**
* 一个辅助方法,执行请求,会自动保持Cookie
*
* @see li.http.Request#execute()
*/
public final Response execute(CookieStore cookieStore) {
this.setCookies(cookieStore.getCookies());
Response response = this.execute();
cookieStore.addAll(response.getCookies());
return response;
}
/**
* 真正发起的GET或者POST请求,会将Cookie转移到Response
*/
public final <T extends Response> T execute(T response) {
try {
String url = this.getUrl();
byte[] data = this.getData();
// 创建 HttpURLConnection , 判断是否 NO_PROXY
HttpURLConnection connection = (HttpURLConnection) (Proxy.NO_PROXY.equals(this.proxy) ? new URL(url).openConnection() : new URL(url).openConnection(this.proxy));
connection.setUseCaches(false);// 不使用缓存
connection.setRequestMethod(this.method);
connection.setReadTimeout(this.readTimeout);
connection.setConnectTimeout(this.connectTimeout);
connection.setInstanceFollowRedirects(this.followRedirects);
for (Entry<String, List<String>> entry : this.headers.entrySet()) {
for (String value : entry.getValue()) {
connection.addRequestProperty(entry.getKey(), value);
}
}
connection.setDoOutput(POST.equalsIgnoreCase(this.method));// post时设置为true
connection.connect();
if (POST.equals(this.method) && null != data) {
connection.getOutputStream().write(data);// post时向服务器写数据
}
response.setHttpURLConnection(connection);
String responseCookies = CookieStore.getCookies(connection.getHeaderFields());// responseCookies
String cookies = null == this.getCookies() ? "" : this.getCookies() + null == responseCookies ? "" : responseCookies;
response.setCookies(Util.stringToCookie(cookies));// 合并requestCookies和responseCookies
return response;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 获取请求地址,此处已添加parameters内容
*/
public final String getUrl() {
if (null == this.urlWithParameters) {
String url = this.url;
if (!url.startsWith("http://") && !url.startsWith("https://")) {// 判断添加http
url = "http://" + url;
}
url += url.contains("?") ? "&" : "?";
for (Entry<String, List<String>> entry : this.parameters.entrySet()) {
for (Object value : entry.getValue()) {
url += entry.getKey() + "=" + value + "&";
}
}
this.urlWithParameters = url.substring(0, url.length() - 1);
}
return this.urlWithParameters;
}
/**
* 若Fields里面包括File或URL则使用getDataMultipart
*/
protected byte[] getData() throws Exception {
for (Entry<String, List<Object>> entry : this.fields.entrySet()) {
for (Object each : entry.getValue()) {
if (each instanceof File || each instanceof URL) {// 本地文件或远程文件
return this.getDataMultipart(); // 有至少一个文件
}
}
}
this.setContentType(FORM_URLENCODED);
return this.getDataUrlEncoded();
}
/**
* 获取fields内容,这个只支持文本域
*/
protected final byte[] getDataUrlEncoded() {
String data = "";
for (Entry<String, List<Object>> entry : this.fields.entrySet()) {
for (Object value : entry.getValue()) {
data += entry.getKey() + "=" + value + "&";
}
}
return data.length() < 1 ? new byte[0] : data.substring(0, data.length() - 1).getBytes();
}
/**
* 获取fields内容,支持文本域和文件(File,URL),注意,这不是一个无损方法,会setContentType
*/
protected final byte[] getDataMultipart() throws Exception {
String FORM_BOUNDARY = "--------------------FormBoundary-----" + UUID.randomUUID();// 分隔符 FormBoundary
this.setContentType("multipart/form-data; boundary=" + FORM_BOUNDARY);// 必须要的,这里不是无损的
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
for (Entry<String, List<Object>> entry : this.fields.entrySet()) {
for (Object each : entry.getValue()) {
byteArrayOutputStream.write(("--" + FORM_BOUNDARY + "\r\n").getBytes());// 每个域的开头
if (each instanceof File || each instanceof URL) {// 本地文件或远程文件
byteArrayOutputStream.write(("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"; filename=\"" + Util.fileName(each) + "\"" + "\r\n").getBytes());// 文件域头
byteArrayOutputStream.write(("Content-Type: " + Util.contentType(each) + "\r\n" + "\r\n").getBytes());
byteArrayOutputStream.write(Util.streamToByteArray(each instanceof File ? new FileInputStream((File) each) : ((URL) each).openStream()));// 文件内容
} else {// 其他,全按照字符串处理
byteArrayOutputStream.write(("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"" + "\r\n").getBytes());// 表单头
byteArrayOutputStream.write(("\r\n" + each).getBytes());// 表单值
}
byteArrayOutputStream.write("\r\n".getBytes());// 换行
}
}
byteArrayOutputStream.write(("--" + FORM_BOUNDARY + "--\r\n").getBytes());// 所有域的结尾
return byteArrayOutputStream.toByteArray();
}
}