对Netty-Http-Client的支持
This commit is contained in:
parent
8bef11f99b
commit
bb18b98538
12
CHANGE.md
12
CHANGE.md
@ -445,8 +445,16 @@
|
||||
|
||||
+ `release`: weixin4j-[mp|qy] upgrade to 1.5.3,weixin4j-server upgrade to 1.0.5
|
||||
|
||||
+ **weixin4j-[mp|qy]**: 媒体接口类(MediaApi)查询素材接口调整:去掉offset,count替换为Pageable类
|
||||
+ **weixin4j-[mp|qy]**: 媒体接口类(MediaApi)查询素材接口调整:去掉offset,count替换为Pageable类
|
||||
|
||||
* 2015-08-18
|
||||
|
||||
+ 比较大的改动:重构了HttpClient部分
|
||||
+ 比较大的改动:重构了HttpClient部分
|
||||
|
||||
* 2015-09-08
|
||||
|
||||
+ weixin4j-mp:新增批量获取用户信息接口
|
||||
|
||||
* 2015-09-10
|
||||
|
||||
+ 对Netty-Http-Client的支持
|
||||
@ -29,5 +29,11 @@
|
||||
<version>4.3</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
<version>4.0.30.Final</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@ -106,4 +106,25 @@ public abstract class AbstractHttpClient implements HttpClient {
|
||||
}
|
||||
return execute(new HttpRequest(method, buf.toString()));
|
||||
}
|
||||
|
||||
protected boolean hasError(HttpStatus status) {
|
||||
return (status.series() == HttpStatus.Series.CLIENT_ERROR || status
|
||||
.series() == HttpStatus.Series.SERVER_ERROR);
|
||||
}
|
||||
|
||||
protected void handleResponse(HttpResponse response)
|
||||
throws HttpClientException {
|
||||
HttpStatus status = response.getStatus();
|
||||
if (hasError(status)) {
|
||||
switch (status.series()) {
|
||||
case CLIENT_ERROR:
|
||||
case SERVER_ERROR:
|
||||
throw new HttpClientException(String.format("%d %s",
|
||||
status.getStatusCode(), status.getStatusText()));
|
||||
default:
|
||||
throw new HttpClientException("Unknown status code [" + status
|
||||
+ "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
package com.foxinmy.weixin4j.http;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
*
|
||||
* @className AbstractHttpResponse
|
||||
* @author jy
|
||||
* @date 2015年9月7日
|
||||
* @since JDK 1.7
|
||||
* @see
|
||||
*/
|
||||
public abstract class AbstractHttpResponse implements HttpResponse {
|
||||
|
||||
private final byte[] content;
|
||||
|
||||
public AbstractHttpResponse(byte[] content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getBody() {
|
||||
return content != null ? new ByteArrayInputStream(content) : null;
|
||||
}
|
||||
}
|
||||
@ -24,14 +24,21 @@ public interface HttpResponse extends HttpMessage {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
HttpStatus getStatus() throws HttpClientException;
|
||||
HttpStatus getStatus();
|
||||
|
||||
/**
|
||||
* 响应内容
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
InputStream getBody() throws HttpClientException;
|
||||
InputStream getBody();
|
||||
|
||||
/**
|
||||
* 响应内容
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
byte[] getContent();
|
||||
|
||||
/**
|
||||
* 释放资源
|
||||
|
||||
@ -31,7 +31,6 @@ package com.foxinmy.weixin4j.http;
|
||||
* Constants enumerating the HTTP status codes. All status codes defined in
|
||||
* RFC1945 (HTTP/1.0), RFC2616 (HTTP/1.1), and RFC2518 (WebDAV) are listed.
|
||||
*
|
||||
* @see StatusLine
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
@ -188,6 +187,54 @@ public final class HttpStatus {
|
||||
return statusText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the HTTP status series of this status code.
|
||||
*
|
||||
* @see HttpStatus.Series
|
||||
*/
|
||||
public Series series() {
|
||||
return Series.valueOf(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Java 5 enumeration of HTTP status series.
|
||||
* <p>
|
||||
* Retrievable via {@link HttpStatus#series()}.
|
||||
*/
|
||||
public static enum Series {
|
||||
|
||||
INFORMATIONAL(1), SUCCESSFUL(2), REDIRECTION(3), CLIENT_ERROR(4), SERVER_ERROR(
|
||||
5);
|
||||
|
||||
private final int value;
|
||||
|
||||
private Series(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the integer value of this status series. Ranges from 1 to 5.
|
||||
*/
|
||||
public int value() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public static Series valueOf(int status) {
|
||||
int seriesCode = status / 100;
|
||||
for (Series series : values()) {
|
||||
if (series.value == seriesCode) {
|
||||
return series;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("No matching constant for ["
|
||||
+ status + "]");
|
||||
}
|
||||
|
||||
public static Series valueOf(HttpStatus status) {
|
||||
return valueOf(status.statusCode);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + statusCode + "," + statusText + "]";
|
||||
|
||||
@ -1,29 +1,24 @@
|
||||
package com.foxinmy.weixin4j.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.Proxy;
|
||||
import java.net.URI;
|
||||
import java.net.URLConnection;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import com.foxinmy.weixin4j.http.entity.HttpEntity;
|
||||
import com.foxinmy.weixin4j.model.Consts;
|
||||
import com.foxinmy.weixin4j.http.factory.HttpClientFactory;
|
||||
import com.foxinmy.weixin4j.util.IOUtil;
|
||||
import com.foxinmy.weixin4j.util.StringUtil;
|
||||
|
||||
/**
|
||||
@ -46,27 +41,6 @@ public class SimpleHttpClient extends AbstractHttpClient implements HttpClient {
|
||||
};
|
||||
}
|
||||
|
||||
protected X509TrustManager createX509TrustManager() {
|
||||
return new X509TrustManager() {
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(
|
||||
X509Certificate[] paramArrayOfX509Certificate,
|
||||
String paramString) throws CertificateException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(
|
||||
X509Certificate[] paramArrayOfX509Certificate,
|
||||
String paramString) throws CertificateException {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected HttpURLConnection createHttpConnection(HttpRequest request)
|
||||
throws IOException {
|
||||
URI uri = request.getURI();
|
||||
@ -83,11 +57,7 @@ public class SimpleHttpClient extends AbstractHttpClient implements HttpClient {
|
||||
hostnameVerifier = params.getHostnameVerifier();
|
||||
}
|
||||
if (sslContext == null) {
|
||||
sslContext = SSLContext.getInstance("TLS");
|
||||
sslContext
|
||||
.init(null,
|
||||
new X509TrustManager[] { createX509TrustManager() },
|
||||
new java.security.SecureRandom());
|
||||
sslContext = HttpClientFactory.allowSSLContext();
|
||||
}
|
||||
if (hostnameVerifier == null) {
|
||||
hostnameVerifier = createHostnameVerifier();
|
||||
@ -96,23 +66,14 @@ public class SimpleHttpClient extends AbstractHttpClient implements HttpClient {
|
||||
connection.setSSLSocketFactory(sslContext.getSocketFactory());
|
||||
connection.setHostnameVerifier(hostnameVerifier);
|
||||
return connection;
|
||||
} catch (NoSuchAlgorithmException | KeyManagementException e) {
|
||||
throw new IOException(e.getMessage());
|
||||
} catch (HttpClientException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
} else {
|
||||
return (HttpURLConnection) urlConnection;
|
||||
}
|
||||
}
|
||||
|
||||
protected Map<String, String> createDefualtHeader() {
|
||||
Map<String, String> header = new HashMap<String, String>();
|
||||
header.put("User-Agent", "simple-httpclient");
|
||||
header.put("Accept", "text/xml,text/javascript");
|
||||
header.put("Accept-Charset", Consts.UTF_8.name());
|
||||
header.put("Accept-Encoding", Consts.UTF_8.name());
|
||||
return header;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpResponse execute(HttpRequest request) throws HttpClientException {
|
||||
HttpResponse response = null;
|
||||
@ -141,25 +102,31 @@ public class SimpleHttpClient extends AbstractHttpClient implements HttpClient {
|
||||
connection.setDoOutput(false);
|
||||
}
|
||||
// set headers
|
||||
for (Iterator<Entry<String, String>> headerIterator = createDefualtHeader()
|
||||
.entrySet().iterator(); headerIterator.hasNext();) {
|
||||
Entry<String, String> header = headerIterator.next();
|
||||
connection.setRequestProperty(header.getKey(),
|
||||
header.getValue());
|
||||
}
|
||||
HttpHeaders headers = request.getHeaders();
|
||||
if (headers != null) {
|
||||
for (Iterator<Entry<String, List<String>>> headerIterator = headers
|
||||
.entrySet().iterator(); headerIterator.hasNext();) {
|
||||
Entry<String, List<String>> header = headerIterator.next();
|
||||
if (HttpHeaders.COOKIE.equalsIgnoreCase(header.getKey())) {
|
||||
connection.setRequestProperty(header.getKey(),
|
||||
StringUtil.join(header.getValue(), ';'));
|
||||
} else {
|
||||
for (String headerValue : header.getValue()) {
|
||||
connection.addRequestProperty(header.getKey(),
|
||||
headerValue != null ? headerValue : "");
|
||||
}
|
||||
if (headers == null) {
|
||||
headers = new HttpHeaders();
|
||||
if (!headers.containsKey(HttpHeaders.HOST)) {
|
||||
headers.set(HttpHeaders.HOST, request.getURI().getHost());
|
||||
}
|
||||
// Add default accept headers
|
||||
if (!headers.containsKey(HttpHeaders.ACCEPT)) {
|
||||
headers.set(HttpHeaders.ACCEPT, "*/*");
|
||||
}
|
||||
// Add default user agent
|
||||
if (!headers.containsKey(HttpHeaders.USER_AGENT)) {
|
||||
headers.set(HttpHeaders.USER_AGENT, "jdk/httpclient");
|
||||
}
|
||||
}
|
||||
for (Iterator<Entry<String, List<String>>> headerIterator = headers
|
||||
.entrySet().iterator(); headerIterator.hasNext();) {
|
||||
Entry<String, List<String>> header = headerIterator.next();
|
||||
if (HttpHeaders.COOKIE.equalsIgnoreCase(header.getKey())) {
|
||||
connection.setRequestProperty(header.getKey(),
|
||||
StringUtil.join(header.getValue(), ';'));
|
||||
} else {
|
||||
for (String headerValue : header.getValue()) {
|
||||
connection.addRequestProperty(header.getKey(),
|
||||
headerValue != null ? headerValue : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -170,16 +137,15 @@ public class SimpleHttpClient extends AbstractHttpClient implements HttpClient {
|
||||
if (httpEntity != null) {
|
||||
// Read Out Exception when connection.disconnect();
|
||||
/*
|
||||
* if (httpEntity.getContentLength() > 0l) {
|
||||
* connection.setFixedLengthStreamingMode(httpEntity
|
||||
* .getContentLength()); } else { connection
|
||||
* .setChunkedStreamingMode(params != null ? params
|
||||
* .getChunkSize() : 4096); }
|
||||
*/
|
||||
if (httpEntity.getContentLength() > 0l) {
|
||||
connection.setFixedLengthStreamingMode(httpEntity
|
||||
.getContentLength());
|
||||
} else {
|
||||
connection
|
||||
.setChunkedStreamingMode(params != null ? params
|
||||
.getChunkSize() : 4096);
|
||||
}*/
|
||||
if (httpEntity.getContentLength() > 0l) {
|
||||
connection.setRequestProperty(HttpHeaders.CONTENT_LENGTH,
|
||||
connection.setRequestProperty(
|
||||
HttpHeaders.CONTENT_LENGTH,
|
||||
Long.toString(httpEntity.getContentLength()));
|
||||
}
|
||||
if (httpEntity.getContentType() != null) {
|
||||
@ -198,7 +164,12 @@ public class SimpleHttpClient extends AbstractHttpClient implements HttpClient {
|
||||
output.close();
|
||||
}
|
||||
// building response
|
||||
response = new SimpleHttpResponse(connection);
|
||||
InputStream input = connection.getErrorStream() != null ? connection
|
||||
.getErrorStream() : connection.getInputStream();
|
||||
byte[] content = IOUtil.toByteArray(input);
|
||||
response = new SimpleHttpResponse(connection, content);
|
||||
input.close();
|
||||
handleResponse(response);
|
||||
} catch (IOException e) {
|
||||
throw new HttpClientException("I/O error on "
|
||||
+ request.getMethod().name() + " request for \""
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package com.foxinmy.weixin4j.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@ -17,7 +16,7 @@ import java.util.Map.Entry;
|
||||
* @since JDK 1.7
|
||||
* @see
|
||||
*/
|
||||
public class SimpleHttpResponse implements HttpResponse {
|
||||
public class SimpleHttpResponse extends AbstractHttpResponse {
|
||||
|
||||
private final HttpURLConnection connection;
|
||||
|
||||
@ -25,7 +24,8 @@ public class SimpleHttpResponse implements HttpResponse {
|
||||
private HttpVersion protocol;
|
||||
private HttpStatus status;
|
||||
|
||||
public SimpleHttpResponse(HttpURLConnection connection) {
|
||||
public SimpleHttpResponse(HttpURLConnection connection, byte[] content) {
|
||||
super(content);
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
@ -65,28 +65,18 @@ public class SimpleHttpResponse implements HttpResponse {
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpStatus getStatus() throws HttpClientException {
|
||||
public HttpStatus getStatus() {
|
||||
if (status == null) {
|
||||
try {
|
||||
status = new HttpStatus(connection.getResponseCode(),
|
||||
connection.getResponseMessage());
|
||||
} catch (IOException e) {
|
||||
throw new HttpClientException("I/O Error on getStatus", e);
|
||||
throw new RuntimeException("I/O Error on getStatus", e);
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getBody() throws HttpClientException {
|
||||
try {
|
||||
return connection.getErrorStream() != null ? connection
|
||||
.getErrorStream() : connection.getInputStream();
|
||||
} catch (IOException e) {
|
||||
throw new HttpClientException("I/O Error on getBody", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
connection.disconnect();
|
||||
|
||||
@ -1,6 +1,15 @@
|
||||
package com.foxinmy.weixin4j.http.factory;
|
||||
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import com.foxinmy.weixin4j.http.HttpClient;
|
||||
import com.foxinmy.weixin4j.http.HttpClientException;
|
||||
|
||||
/**
|
||||
* HttpClient工厂生产类:参考netty的InternalLoggerFactory
|
||||
@ -26,12 +35,16 @@ public abstract class HttpClientFactory {
|
||||
private static HttpClientFactory newDefaultFactory() {
|
||||
HttpClientFactory f;
|
||||
try {
|
||||
f = new HttpComponent4Factory();
|
||||
} catch (Throwable e2) {
|
||||
f = new Netty4HttpClientFactory();
|
||||
} catch (Throwable e1) {
|
||||
try {
|
||||
f = new HttpComponent3Factory();
|
||||
} catch (Throwable e3) {
|
||||
f = new SimpleHttpClientFactory();
|
||||
f = new HttpComponent4Factory();
|
||||
} catch (Throwable e2) {
|
||||
try {
|
||||
f = new HttpComponent3Factory();
|
||||
} catch (Throwable e3) {
|
||||
f = new SimpleHttpClientFactory();
|
||||
}
|
||||
}
|
||||
}
|
||||
return f;
|
||||
@ -73,4 +86,37 @@ public abstract class HttpClientFactory {
|
||||
* @return
|
||||
*/
|
||||
public abstract HttpClient newInstance();
|
||||
|
||||
public static SSLContext allowSSLContext() throws HttpClientException {
|
||||
try {
|
||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||
sslContext.init(null,
|
||||
new X509TrustManager[] { createX509TrustManager() },
|
||||
new java.security.SecureRandom());
|
||||
return sslContext;
|
||||
} catch (NoSuchAlgorithmException | KeyManagementException e) {
|
||||
throw new HttpClientException("Create SSLContext Error:", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected static X509TrustManager createX509TrustManager() {
|
||||
return new X509TrustManager() {
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(
|
||||
X509Certificate[] paramArrayOfX509Certificate,
|
||||
String paramString) throws CertificateException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(
|
||||
X509Certificate[] paramArrayOfX509Certificate,
|
||||
String paramString) throws CertificateException {
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,18 +109,30 @@ public class HttpComponent3 extends AbstractHttpClient {
|
||||
}
|
||||
com.foxinmy.weixin4j.http.HttpHeaders headers = request
|
||||
.getHeaders();
|
||||
if (headers != null) {
|
||||
for (Iterator<Entry<String, List<String>>> headerIterator = headers
|
||||
.entrySet().iterator(); headerIterator.hasNext();) {
|
||||
Entry<String, List<String>> header = headerIterator.next();
|
||||
if (HttpHeaders.COOKIE.equalsIgnoreCase(header.getKey())) {
|
||||
httpMethod.setRequestHeader(header.getKey(),
|
||||
StringUtil.join(header.getValue(), ';'));
|
||||
} else {
|
||||
for (String headerValue : header.getValue()) {
|
||||
httpMethod.addRequestHeader(header.getKey(),
|
||||
headerValue != null ? headerValue : "");
|
||||
}
|
||||
if (headers == null) {
|
||||
headers = new HttpHeaders();
|
||||
}
|
||||
if (!headers.containsKey(HttpHeaders.HOST)) {
|
||||
headers.set(HttpHeaders.HOST, uri.getHost());
|
||||
}
|
||||
// Add default accept headers
|
||||
if (!headers.containsKey(HttpHeaders.ACCEPT)) {
|
||||
headers.set(HttpHeaders.ACCEPT, "*/*");
|
||||
}
|
||||
// Add default user agent
|
||||
if (!headers.containsKey(HttpHeaders.USER_AGENT)) {
|
||||
headers.set(HttpHeaders.USER_AGENT, "apache/httpclient3");
|
||||
}
|
||||
for (Iterator<Entry<String, List<String>>> headerIterator = headers
|
||||
.entrySet().iterator(); headerIterator.hasNext();) {
|
||||
Entry<String, List<String>> header = headerIterator.next();
|
||||
if (HttpHeaders.COOKIE.equalsIgnoreCase(header.getKey())) {
|
||||
httpMethod.setRequestHeader(header.getKey(),
|
||||
StringUtil.join(header.getValue(), ';'));
|
||||
} else {
|
||||
for (String headerValue : header.getValue()) {
|
||||
httpMethod.addRequestHeader(header.getKey(),
|
||||
headerValue != null ? headerValue : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -153,6 +165,7 @@ public class HttpComponent3 extends AbstractHttpClient {
|
||||
}
|
||||
httpClient.executeMethod(httpMethod);
|
||||
response = new HttpComponent3Response(httpMethod);
|
||||
handleResponse(response);
|
||||
} catch (IOException e) {
|
||||
throw new HttpClientException("I/O error on "
|
||||
+ request.getMethod().name() + " request for \""
|
||||
|
||||
@ -1,16 +1,13 @@
|
||||
package com.foxinmy.weixin4j.http.factory;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.apache.commons.httpclient.Header;
|
||||
import org.apache.commons.httpclient.HttpMethod;
|
||||
import org.apache.commons.httpclient.protocol.Protocol;
|
||||
|
||||
import com.foxinmy.weixin4j.http.HttpClientException;
|
||||
import com.foxinmy.weixin4j.http.AbstractHttpResponse;
|
||||
import com.foxinmy.weixin4j.http.HttpHeaders;
|
||||
import com.foxinmy.weixin4j.http.HttpResponse;
|
||||
import com.foxinmy.weixin4j.http.HttpStatus;
|
||||
import com.foxinmy.weixin4j.http.HttpVersion;
|
||||
|
||||
@ -23,22 +20,17 @@ import com.foxinmy.weixin4j.http.HttpVersion;
|
||||
* @since JDK 1.7
|
||||
* @see
|
||||
*/
|
||||
public class HttpComponent3Response implements HttpResponse {
|
||||
public class HttpComponent3Response extends AbstractHttpResponse {
|
||||
|
||||
private final HttpMethod httpMethod;
|
||||
|
||||
private HttpHeaders headers;
|
||||
private HttpVersion protocol;
|
||||
private HttpStatus status;
|
||||
private InputStream body;
|
||||
|
||||
public HttpComponent3Response(HttpMethod httpMethod) {
|
||||
public HttpComponent3Response(HttpMethod httpMethod) throws IOException {
|
||||
super(httpMethod.getResponseBody());
|
||||
this.httpMethod = httpMethod;
|
||||
try {
|
||||
this.body = new ByteArrayInputStream(httpMethod.getResponseBody());
|
||||
} catch (IOException e) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -71,7 +63,7 @@ public class HttpComponent3Response implements HttpResponse {
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpStatus getStatus() throws HttpClientException {
|
||||
public HttpStatus getStatus() {
|
||||
if (status == null) {
|
||||
status = new HttpStatus(httpMethod.getStatusCode(),
|
||||
httpMethod.getStatusText());
|
||||
@ -79,11 +71,6 @@ public class HttpComponent3Response implements HttpResponse {
|
||||
return status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getBody() throws HttpClientException {
|
||||
return body;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
httpMethod.releaseConnection();
|
||||
|
||||
@ -26,6 +26,7 @@ import org.apache.http.client.methods.HttpTrace;
|
||||
import org.apache.http.conn.ssl.X509HostnameVerifier;
|
||||
import org.apache.http.entity.AbstractHttpEntity;
|
||||
import org.apache.http.entity.InputStreamEntity;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
|
||||
import com.foxinmy.weixin4j.http.AbstractHttpClient;
|
||||
import com.foxinmy.weixin4j.http.HttpHeaders;
|
||||
@ -57,18 +58,27 @@ public abstract class HttpComponent4 extends AbstractHttpClient {
|
||||
}
|
||||
|
||||
protected void addHeaders(HttpHeaders headers, HttpRequestBase uriRequest) {
|
||||
if (headers != null) {
|
||||
for (Iterator<Entry<String, List<String>>> headerIterator = headers
|
||||
.entrySet().iterator(); headerIterator.hasNext();) {
|
||||
Entry<String, List<String>> header = headerIterator.next();
|
||||
if (HttpHeaders.COOKIE.equalsIgnoreCase(header.getKey())) {
|
||||
if (headers == null) {
|
||||
headers = new HttpHeaders();
|
||||
}
|
||||
// Add default accept headers
|
||||
if (!headers.containsKey(HttpHeaders.ACCEPT)) {
|
||||
headers.set(HttpHeaders.ACCEPT, "*/*");
|
||||
}
|
||||
// Add default user agent
|
||||
if (!headers.containsKey(HttpHeaders.USER_AGENT)) {
|
||||
headers.set(HttpHeaders.USER_AGENT, "apache/httpclient4");
|
||||
}
|
||||
for (Iterator<Entry<String, List<String>>> headerIterator = headers
|
||||
.entrySet().iterator(); headerIterator.hasNext();) {
|
||||
Entry<String, List<String>> header = headerIterator.next();
|
||||
if (HttpHeaders.COOKIE.equalsIgnoreCase(header.getKey())) {
|
||||
uriRequest.addHeader(header.getKey(),
|
||||
StringUtil.join(header.getValue(), ';'));
|
||||
} else {
|
||||
for (String headerValue : header.getValue()) {
|
||||
uriRequest.addHeader(header.getKey(),
|
||||
StringUtil.join(header.getValue(), ';'));
|
||||
} else {
|
||||
for (String headerValue : header.getValue()) {
|
||||
uriRequest.addHeader(header.getKey(),
|
||||
headerValue != null ? headerValue : "");
|
||||
}
|
||||
headerValue != null ? headerValue : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -94,6 +104,11 @@ public abstract class HttpComponent4 extends AbstractHttpClient {
|
||||
}
|
||||
}
|
||||
|
||||
protected byte[] getContent(org.apache.http.HttpResponse httpResponse)
|
||||
throws IOException {
|
||||
return EntityUtils.toByteArray(httpResponse.getEntity());
|
||||
}
|
||||
|
||||
protected static class CustomHostnameVerifier implements
|
||||
X509HostnameVerifier {
|
||||
|
||||
|
||||
@ -13,7 +13,6 @@ import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.apache.http.params.CoreConnectionPNames;
|
||||
import org.apache.http.params.CoreProtocolPNames;
|
||||
|
||||
import com.foxinmy.weixin4j.http.HttpClient;
|
||||
import com.foxinmy.weixin4j.http.HttpClientException;
|
||||
import com.foxinmy.weixin4j.http.HttpHeaders;
|
||||
import com.foxinmy.weixin4j.http.HttpParams;
|
||||
@ -87,7 +86,9 @@ public class HttpComponent4_1 extends HttpComponent4 {
|
||||
addEntity(request.getEntity(), uriRequest);
|
||||
org.apache.http.HttpResponse httpResponse = httpClient
|
||||
.execute(uriRequest);
|
||||
response = new HttpComponent4_1Response(httpClient, httpResponse);
|
||||
response = new HttpComponent4_1Response(httpResponse,
|
||||
getContent(httpResponse));
|
||||
handleResponse(response);
|
||||
} catch (IOException e) {
|
||||
throw new HttpClientException("I/O error on "
|
||||
+ request.getMethod().name() + " request for \""
|
||||
|
||||
@ -1,16 +1,13 @@
|
||||
package com.foxinmy.weixin4j.http.factory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.ProtocolVersion;
|
||||
import org.apache.http.StatusLine;
|
||||
|
||||
import com.foxinmy.weixin4j.http.HttpClientException;
|
||||
import com.foxinmy.weixin4j.http.AbstractHttpResponse;
|
||||
import com.foxinmy.weixin4j.http.HttpHeaders;
|
||||
import com.foxinmy.weixin4j.http.HttpResponse;
|
||||
import com.foxinmy.weixin4j.http.HttpStatus;
|
||||
import com.foxinmy.weixin4j.http.HttpVersion;
|
||||
|
||||
@ -23,18 +20,16 @@ import com.foxinmy.weixin4j.http.HttpVersion;
|
||||
* @since JDK 1.7
|
||||
* @see
|
||||
*/
|
||||
public class HttpComponent4_1Response implements HttpResponse {
|
||||
private final org.apache.http.client.HttpClient httpClient;
|
||||
public class HttpComponent4_1Response extends AbstractHttpResponse {
|
||||
private final org.apache.http.HttpResponse httpResponse;
|
||||
|
||||
private HttpHeaders headers;
|
||||
private HttpVersion protocol;
|
||||
private HttpStatus status;
|
||||
|
||||
public HttpComponent4_1Response(
|
||||
org.apache.http.client.HttpClient httpClient,
|
||||
org.apache.http.HttpResponse httpResponse) {
|
||||
this.httpClient = httpClient;
|
||||
public HttpComponent4_1Response(org.apache.http.HttpResponse httpResponse,
|
||||
byte[] content) throws IOException {
|
||||
super(content);
|
||||
this.httpResponse = httpResponse;
|
||||
}
|
||||
|
||||
@ -64,7 +59,7 @@ public class HttpComponent4_1Response implements HttpResponse {
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpStatus getStatus() throws HttpClientException {
|
||||
public HttpStatus getStatus() {
|
||||
if (status == null) {
|
||||
StatusLine statusLine = httpResponse.getStatusLine();
|
||||
status = new HttpStatus(statusLine.getStatusCode(),
|
||||
@ -74,17 +69,11 @@ public class HttpComponent4_1Response implements HttpResponse {
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getBody() throws HttpClientException {
|
||||
public void close() {
|
||||
try {
|
||||
HttpEntity entity = this.httpResponse.getEntity();
|
||||
return (entity != null ? entity.getContent() : null);
|
||||
httpResponse.getEntity().consumeContent();
|
||||
} catch (IOException e) {
|
||||
throw new HttpClientException("I/O Error on getBody", e);
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
httpClient.getConnectionManager().closeExpiredConnections();
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,7 +69,9 @@ public class HttpComponent4_2 extends HttpComponent4 {
|
||||
addHeaders(request.getHeaders(), uriRequest);
|
||||
addEntity(request.getEntity(), uriRequest);
|
||||
CloseableHttpResponse httpResponse = httpClient.execute(uriRequest);
|
||||
response = new HttpComponent4_2Response(httpResponse);
|
||||
response = new HttpComponent4_2Response(httpResponse,
|
||||
getContent(httpResponse));
|
||||
handleResponse(response);
|
||||
} catch (IOException e) {
|
||||
throw new HttpClientException("I/O error on "
|
||||
+ request.getMethod().name() + " request for \""
|
||||
|
||||
@ -1,17 +1,15 @@
|
||||
package com.foxinmy.weixin4j.http.factory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.ProtocolVersion;
|
||||
import org.apache.http.StatusLine;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
|
||||
import com.foxinmy.weixin4j.http.HttpClientException;
|
||||
import com.foxinmy.weixin4j.http.AbstractHttpResponse;
|
||||
import com.foxinmy.weixin4j.http.HttpHeaders;
|
||||
import com.foxinmy.weixin4j.http.HttpResponse;
|
||||
import com.foxinmy.weixin4j.http.HttpStatus;
|
||||
import com.foxinmy.weixin4j.http.HttpVersion;
|
||||
|
||||
@ -24,7 +22,7 @@ import com.foxinmy.weixin4j.http.HttpVersion;
|
||||
* @since JDK 1.7
|
||||
* @see
|
||||
*/
|
||||
public class HttpComponent4_2Response implements HttpResponse {
|
||||
public class HttpComponent4_2Response extends AbstractHttpResponse {
|
||||
|
||||
private final CloseableHttpResponse httpResponse;
|
||||
|
||||
@ -32,7 +30,9 @@ public class HttpComponent4_2Response implements HttpResponse {
|
||||
private HttpVersion protocol;
|
||||
private HttpStatus status;
|
||||
|
||||
public HttpComponent4_2Response(CloseableHttpResponse httpResponse) {
|
||||
public HttpComponent4_2Response(CloseableHttpResponse httpResponse,
|
||||
byte[] content) {
|
||||
super(content);
|
||||
this.httpResponse = httpResponse;
|
||||
}
|
||||
|
||||
@ -62,7 +62,7 @@ public class HttpComponent4_2Response implements HttpResponse {
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpStatus getStatus() throws HttpClientException {
|
||||
public HttpStatus getStatus() {
|
||||
if (status == null) {
|
||||
StatusLine statusLine = httpResponse.getStatusLine();
|
||||
status = new HttpStatus(statusLine.getStatusCode(),
|
||||
@ -71,20 +71,10 @@ public class HttpComponent4_2Response implements HttpResponse {
|
||||
return status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getBody() throws HttpClientException {
|
||||
try {
|
||||
HttpEntity entity = this.httpResponse.getEntity();
|
||||
return (entity != null ? entity.getContent() : null);
|
||||
} catch (IOException e) {
|
||||
throw new HttpClientException("I/O Error on getBody", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
// EntityUtils.consume(httpResponse.getEntity());
|
||||
EntityUtils.consume(httpResponse.getEntity());
|
||||
httpResponse.close();
|
||||
} catch (IOException ex) {
|
||||
;
|
||||
|
||||
@ -0,0 +1,223 @@
|
||||
package com.foxinmy.weixin4j.http.factory;
|
||||
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import io.netty.buffer.ByteBufOutputStream;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpRequest;
|
||||
import io.netty.handler.codec.http.DefaultHttpRequest;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpMethod;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
import io.netty.handler.ssl.SslHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URI;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
|
||||
import com.foxinmy.weixin4j.http.AbstractHttpClient;
|
||||
import com.foxinmy.weixin4j.http.HttpClientException;
|
||||
import com.foxinmy.weixin4j.http.HttpHeaders;
|
||||
import com.foxinmy.weixin4j.http.HttpParams;
|
||||
import com.foxinmy.weixin4j.http.HttpRequest;
|
||||
import com.foxinmy.weixin4j.http.HttpResponse;
|
||||
import com.foxinmy.weixin4j.http.entity.HttpEntity;
|
||||
import com.foxinmy.weixin4j.util.SettableFuture;
|
||||
import com.foxinmy.weixin4j.util.StringUtil;
|
||||
|
||||
/**
|
||||
* Netty 4.x
|
||||
*
|
||||
* @className Netty4HttpClient
|
||||
* @author jy
|
||||
* @date 2015年8月30日
|
||||
* @since JDK 1.7
|
||||
* @see
|
||||
*/
|
||||
public class Netty4HttpClient extends AbstractHttpClient {
|
||||
|
||||
private final Bootstrap bootstrap;
|
||||
|
||||
public Netty4HttpClient(Bootstrap bootstrap) {
|
||||
this.bootstrap = bootstrap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpResponse execute(HttpRequest request) throws HttpClientException {
|
||||
HttpResponse response = null;
|
||||
try {
|
||||
final URI uri = request.getURI();
|
||||
final HttpParams params = request.getParams();
|
||||
if (params != null) {
|
||||
bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS,
|
||||
params.getConnectTimeout());
|
||||
}
|
||||
final boolean useProxy = params != null
|
||||
&& params.getProxy() != null;
|
||||
final boolean useSSL = "https".equals(uri.getScheme()) && !useProxy;
|
||||
final DefaultHttpRequest uriRequest = createRequest(request);
|
||||
final SettableFuture<HttpResponse> future = new SettableFuture<HttpResponse>();
|
||||
ChannelFutureListener listener = new ChannelFutureListener() {
|
||||
@Override
|
||||
public void operationComplete(ChannelFuture channelFuture)
|
||||
throws Exception {
|
||||
if (channelFuture.isSuccess()) {
|
||||
Channel channel = channelFuture.channel();
|
||||
// ssl
|
||||
SSLContext sslContext = null;
|
||||
if (useSSL) {
|
||||
if (params != null
|
||||
&& params.getSSLContext() != null) {
|
||||
sslContext = params.getSSLContext();
|
||||
} else {
|
||||
sslContext = HttpClientFactory
|
||||
.allowSSLContext();
|
||||
}
|
||||
SSLEngine sslEngine = sslContext.createSSLEngine();
|
||||
sslEngine.setUseClientMode(true);
|
||||
channel.pipeline().addFirst(
|
||||
new SslHandler(sslEngine));
|
||||
}
|
||||
channel.pipeline().addLast(new RequestHandler(future));
|
||||
channel.writeAndFlush(uriRequest);
|
||||
} else {
|
||||
future.setException(channelFuture.cause());
|
||||
}
|
||||
}
|
||||
};
|
||||
InetSocketAddress address = new InetSocketAddress(
|
||||
InetAddress.getByName(uri.getHost()), getPort(uri));
|
||||
if (useProxy) {
|
||||
address = (InetSocketAddress) params.getProxy().address();
|
||||
}
|
||||
bootstrap.connect(address).syncUninterruptibly()
|
||||
.addListener(listener);
|
||||
response = future.get();
|
||||
handleResponse(response);
|
||||
} catch (IOException | InterruptedException | ExecutionException e) {
|
||||
throw new HttpClientException("I/O error on "
|
||||
+ request.getMethod().name() + " request for \""
|
||||
+ request.getURI().toString() + "\":" + e.getMessage(), e);
|
||||
} finally {
|
||||
if (response != null) {
|
||||
response.close();
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
private DefaultHttpRequest createRequest(HttpRequest request)
|
||||
throws IOException {
|
||||
HttpMethod method = HttpMethod.valueOf(request.getMethod().name());
|
||||
URI uri = request.getURI();
|
||||
String url = StringUtil.isBlank(uri.getRawPath()) ? "/" : uri
|
||||
.getRawPath();
|
||||
if (StringUtil.isNotBlank(uri.getRawQuery())) {
|
||||
url += "?" + uri.getRawQuery();
|
||||
}
|
||||
DefaultHttpRequest uriRequest = new DefaultHttpRequest(
|
||||
HttpVersion.HTTP_1_1, method, url);
|
||||
// entity
|
||||
HttpEntity entity = request.getEntity();
|
||||
if (entity != null) {
|
||||
ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer();
|
||||
try (ByteBufOutputStream out = new ByteBufOutputStream(byteBuf)) {
|
||||
entity.writeTo(out);
|
||||
}
|
||||
uriRequest = new DefaultFullHttpRequest(
|
||||
uriRequest.getProtocolVersion(), uriRequest.getMethod(),
|
||||
uriRequest.getUri(), byteBuf);
|
||||
if (entity.getContentType() != null) {
|
||||
uriRequest.headers().add(HttpHeaders.CONTENT_TYPE,
|
||||
entity.getContentType().toString());
|
||||
}
|
||||
if (entity.getContentLength() < 0) {
|
||||
uriRequest.headers().add(HttpHeaders.TRANSFER_ENCODING,
|
||||
io.netty.handler.codec.http.HttpHeaders.Values.CHUNKED);
|
||||
} else {
|
||||
uriRequest.headers().add(HttpHeaders.CONTENT_LENGTH,
|
||||
entity.getContentLength());
|
||||
}
|
||||
}
|
||||
// header
|
||||
HttpHeaders headers = request.getHeaders();
|
||||
if (headers == null) {
|
||||
headers = new HttpHeaders();
|
||||
}
|
||||
if (!headers.containsKey(HttpHeaders.HOST)) {
|
||||
headers.set(HttpHeaders.HOST, uri.getHost());
|
||||
}
|
||||
// Add default accept headers
|
||||
if (!headers.containsKey(HttpHeaders.ACCEPT)) {
|
||||
headers.set(HttpHeaders.ACCEPT, "*/*");
|
||||
}
|
||||
// Add default user agent
|
||||
if (!headers.containsKey(HttpHeaders.USER_AGENT)) {
|
||||
headers.set(HttpHeaders.USER_AGENT, "netty/httpclient");
|
||||
}
|
||||
for (Iterator<Entry<String, List<String>>> headerIterator = headers
|
||||
.entrySet().iterator(); headerIterator.hasNext();) {
|
||||
Entry<String, List<String>> header = headerIterator.next();
|
||||
uriRequest.headers().add(header.getKey(), header.getValue());
|
||||
}
|
||||
uriRequest.headers().set(HttpHeaders.CONNECTION,
|
||||
io.netty.handler.codec.http.HttpHeaders.Values.CLOSE);
|
||||
return uriRequest;
|
||||
}
|
||||
|
||||
private int getPort(URI uri) {
|
||||
int port = uri.getPort();
|
||||
if (port == -1) {
|
||||
if ("http".equalsIgnoreCase(uri.getScheme())) {
|
||||
port = 80;
|
||||
} else if ("https".equalsIgnoreCase(uri.getScheme())) {
|
||||
port = 443;
|
||||
}
|
||||
}
|
||||
return port;
|
||||
}
|
||||
|
||||
private static class RequestHandler extends
|
||||
SimpleChannelInboundHandler<FullHttpResponse> {
|
||||
|
||||
private final SettableFuture<HttpResponse> future;
|
||||
|
||||
public RequestHandler(SettableFuture<HttpResponse> future) {
|
||||
this.future = future;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext context,
|
||||
FullHttpResponse response) throws Exception {
|
||||
byte[] content = null;
|
||||
ByteBuf byteBuf = response.content();
|
||||
if (byteBuf.hasArray()) {
|
||||
content = byteBuf.array();
|
||||
} else {
|
||||
content = new byte[byteBuf.readableBytes()];
|
||||
byteBuf.readBytes(content);
|
||||
}
|
||||
future.set(new Netty4HttpResponse(context, response, content));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext context,
|
||||
Throwable cause) throws Exception {
|
||||
future.setException(cause);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
package com.foxinmy.weixin4j.http.factory;
|
||||
|
||||
import io.netty.bootstrap.Bootstrap;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.handler.codec.http.HttpClientCodec;
|
||||
import io.netty.handler.codec.http.HttpContentDecompressor;
|
||||
import io.netty.handler.codec.http.HttpObjectAggregator;
|
||||
import io.netty.handler.codec.http.HttpResponseDecoder;
|
||||
import io.netty.handler.stream.ChunkedWriteHandler;
|
||||
|
||||
import com.foxinmy.weixin4j.http.HttpClient;
|
||||
|
||||
/**
|
||||
* 使用Netty
|
||||
*
|
||||
* @className Netty4HttpClientFactory
|
||||
* @author jy
|
||||
* @date 2015年8月30日
|
||||
* @since JDK 1.7
|
||||
* @see
|
||||
*/
|
||||
public class Netty4HttpClientFactory extends HttpClientFactory {
|
||||
/**
|
||||
* worker线程数,默认设置为cpu的核数 * 4
|
||||
*/
|
||||
private final int workerThreads;
|
||||
|
||||
public Netty4HttpClientFactory() {
|
||||
this(Runtime.getRuntime().availableProcessors() * 4);
|
||||
}
|
||||
|
||||
public Netty4HttpClientFactory(int workerThreads) {
|
||||
this.workerThreads = workerThreads;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpClient newInstance() {
|
||||
Bootstrap b = new Bootstrap();
|
||||
b.option(ChannelOption.SO_KEEPALIVE, true).option(
|
||||
ChannelOption.TCP_NODELAY, true);
|
||||
EventLoopGroup workerGroup = new NioEventLoopGroup(workerThreads);
|
||||
b.group(workerGroup).channel(NioSocketChannel.class)
|
||||
.handler(new ChannelInitializer<SocketChannel>() {
|
||||
@Override
|
||||
protected void initChannel(SocketChannel channel)
|
||||
throws Exception {
|
||||
ChannelPipeline pipeline = channel.pipeline();
|
||||
pipeline.addLast(new HttpClientCodec());
|
||||
pipeline.addLast(new HttpContentDecompressor());
|
||||
pipeline.addLast(new ChunkedWriteHandler());
|
||||
pipeline.addLast(new HttpResponseDecoder());
|
||||
pipeline.addLast(new HttpObjectAggregator(
|
||||
Integer.MAX_VALUE));
|
||||
}
|
||||
});
|
||||
return new Netty4HttpClient(b);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
package com.foxinmy.weixin4j.http.factory;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.foxinmy.weixin4j.http.AbstractHttpResponse;
|
||||
import com.foxinmy.weixin4j.http.HttpHeaders;
|
||||
import com.foxinmy.weixin4j.http.HttpStatus;
|
||||
import com.foxinmy.weixin4j.http.HttpVersion;
|
||||
|
||||
/**
|
||||
* Netty Respone::Requires Netty 4.x or higher
|
||||
*
|
||||
* @className Netty4HttpResponse
|
||||
* @author jy
|
||||
* @date 2015年8月30日
|
||||
* @since JDK 1.7
|
||||
* @see
|
||||
*/
|
||||
public class Netty4HttpResponse extends AbstractHttpResponse {
|
||||
|
||||
private final ChannelHandlerContext context;
|
||||
private final FullHttpResponse response;
|
||||
|
||||
private HttpVersion protocol;
|
||||
private HttpStatus status;
|
||||
private volatile HttpHeaders headers;
|
||||
|
||||
public Netty4HttpResponse(ChannelHandlerContext context,
|
||||
FullHttpResponse response, byte[] content) {
|
||||
super(content);
|
||||
this.context = context;
|
||||
this.response = response;
|
||||
this.response.retain();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders getHeaders() {
|
||||
if (this.headers == null) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
for (Map.Entry<String, String> entry : this.response.headers()) {
|
||||
headers.add(entry.getKey(), entry.getValue());
|
||||
}
|
||||
this.headers = headers;
|
||||
}
|
||||
return this.headers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpVersion getProtocol() {
|
||||
if (protocol == null) {
|
||||
io.netty.handler.codec.http.HttpVersion version = response
|
||||
.getProtocolVersion();
|
||||
this.protocol = new HttpVersion(version.protocolName(),
|
||||
version.majorVersion(), version.majorVersion(),
|
||||
version.isKeepAliveDefault());
|
||||
}
|
||||
return protocol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpStatus getStatus() {
|
||||
if (status == null) {
|
||||
HttpResponseStatus status = response.getStatus();
|
||||
this.status = new HttpStatus(status.code(), status.reasonPhrase());
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
this.response.release();
|
||||
this.context.close();
|
||||
}
|
||||
}
|
||||
@ -20,6 +20,7 @@ import com.foxinmy.weixin4j.http.entity.FormUrlEntity;
|
||||
import com.foxinmy.weixin4j.http.entity.HttpEntity;
|
||||
import com.foxinmy.weixin4j.http.entity.StringEntity;
|
||||
import com.foxinmy.weixin4j.http.factory.HttpClientFactory;
|
||||
import com.foxinmy.weixin4j.http.factory.Netty4HttpClientFactory;
|
||||
import com.foxinmy.weixin4j.model.Consts;
|
||||
import com.foxinmy.weixin4j.util.StringUtil;
|
||||
import com.foxinmy.weixin4j.util.WeixinErrorUtil;
|
||||
@ -44,6 +45,7 @@ public class WeixinRequestExecutor {
|
||||
}
|
||||
|
||||
public WeixinRequestExecutor(HttpParams params) {
|
||||
HttpClientFactory.setDefaultFactory(new Netty4HttpClientFactory());
|
||||
this.httpClient = HttpClientFactory.getInstance();
|
||||
this.params = params;
|
||||
}
|
||||
@ -97,10 +99,6 @@ public class WeixinRequestExecutor {
|
||||
HttpResponse httpResponse = httpClient.execute(request);
|
||||
HttpStatus status = httpResponse.getStatus();
|
||||
HttpHeaders headers = httpResponse.getHeaders();
|
||||
if (status.getStatusCode() >= HttpStatus.SC_MULTIPLE_CHOICES) {
|
||||
throw new WeixinException(String.format("request fail : %d-%s",
|
||||
status.getStatusCode(), status.getStatusText()));
|
||||
}
|
||||
WeixinResponse response = new WeixinResponse(headers, status,
|
||||
httpResponse.getBody());
|
||||
String contentType = headers.getFirst(HttpHeaders.CONTENT_TYPE);
|
||||
|
||||
@ -42,6 +42,7 @@ public class WeixinResponse {
|
||||
try {
|
||||
text = StringUtil.newStringUtf8(IOUtil.toByteArray(body));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* 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.foxinmy.weixin4j.util;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* A {@link org.springframework.util.concurrent.ListenableFuture
|
||||
* ListenableFuture} whose value can be set via {@link #set(Object)} or
|
||||
* {@link #setException(Throwable)}. It may also be cancelled.
|
||||
*
|
||||
* <p>
|
||||
* Inspired by {@code com.google.common.util.concurrent.SettableFuture}.
|
||||
*
|
||||
* @author Mattias Severson
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 4.1
|
||||
*/
|
||||
public class SettableFuture<T> implements Future<T> {
|
||||
|
||||
private final SettableTask<T> settableTask;
|
||||
|
||||
private final FutureTask<T> futureTask;
|
||||
|
||||
public SettableFuture() {
|
||||
this.settableTask = new SettableTask<T>();
|
||||
this.futureTask = new FutureTask<T>(this.settableTask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of this future. This method will return {@code true} if the
|
||||
* value was set successfully, or {@code false} if the future has already
|
||||
* been set or cancelled.
|
||||
*
|
||||
* @param value
|
||||
* the value that will be set.
|
||||
* @return {@code true} if the value was successfully set, else
|
||||
* {@code false}.
|
||||
*/
|
||||
public boolean set(T value) {
|
||||
boolean success = this.settableTask.setValue(value);
|
||||
if (success) {
|
||||
this.futureTask.run();
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the exception of this future. This method will return {@code true} if
|
||||
* the exception was set successfully, or {@code false} if the future has
|
||||
* already been set or cancelled.
|
||||
*
|
||||
* @param exception
|
||||
* the value that will be set.
|
||||
* @return {@code true} if the exception was successfully set, else
|
||||
* {@code false}.
|
||||
*/
|
||||
public boolean setException(Throwable exception) {
|
||||
boolean success = this.settableTask.setException(exception);
|
||||
if (success) {
|
||||
this.futureTask.run();
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
this.settableTask.setCancelled();
|
||||
boolean cancelled = this.futureTask.cancel(mayInterruptIfRunning);
|
||||
if (cancelled && mayInterruptIfRunning) {
|
||||
interruptTask();
|
||||
}
|
||||
return cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return this.futureTask.isCancelled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
return this.futureTask.isDone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the value.
|
||||
* <p>
|
||||
* Will return the value if it has been set via {@link #set(Object)}, throw
|
||||
* an {@link java.util.concurrent.ExecutionException} if it has been set via
|
||||
* {@link #setException(Throwable)} or throw a
|
||||
* {@link java.util.concurrent.CancellationException} if it has been
|
||||
* cancelled.
|
||||
*
|
||||
* @return The value associated with this future.
|
||||
*/
|
||||
@Override
|
||||
public T get() throws InterruptedException, ExecutionException {
|
||||
return this.futureTask.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the value.
|
||||
* <p>
|
||||
* Will return the value if it has been set via {@link #set(Object)}, throw
|
||||
* an {@link java.util.concurrent.ExecutionException} if it has been set via
|
||||
* {@link #setException(Throwable)} or throw a
|
||||
* {@link java.util.concurrent.CancellationException} if it has been
|
||||
* cancelled.
|
||||
*
|
||||
* @param timeout
|
||||
* the maximum time to wait.
|
||||
* @param unit
|
||||
* the time unit of the timeout argument.
|
||||
* @return The value associated with this future.
|
||||
*/
|
||||
@Override
|
||||
public T get(long timeout, TimeUnit unit) throws InterruptedException,
|
||||
ExecutionException, TimeoutException {
|
||||
return this.futureTask.get(timeout, unit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses can override this method to implement interruption of the
|
||||
* future's computation. The method is invoked automatically by a successful
|
||||
* call to {@link #cancel(boolean) cancel(true)}.
|
||||
* <p>
|
||||
* The default implementation does nothing.
|
||||
*/
|
||||
protected void interruptTask() {
|
||||
}
|
||||
|
||||
private static class SettableTask<T> implements Callable<T> {
|
||||
|
||||
private static final String NO_VALUE = SettableFuture.class
|
||||
.getName() + ".NO_VALUE";
|
||||
|
||||
private final AtomicReference<Object> value = new AtomicReference<Object>(
|
||||
NO_VALUE);
|
||||
|
||||
private volatile boolean cancelled = false;
|
||||
|
||||
public boolean setValue(T value) {
|
||||
if (this.cancelled) {
|
||||
return false;
|
||||
}
|
||||
return this.value.compareAndSet(NO_VALUE, value);
|
||||
}
|
||||
|
||||
public boolean setException(Throwable exception) {
|
||||
if (this.cancelled) {
|
||||
return false;
|
||||
}
|
||||
return this.value.compareAndSet(NO_VALUE, exception);
|
||||
}
|
||||
|
||||
public void setCancelled() {
|
||||
this.cancelled = true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public T call() throws Exception {
|
||||
if (value.get() instanceof Exception) {
|
||||
throw (Exception) value.get();
|
||||
}
|
||||
return (T) value.get();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,6 +1,9 @@
|
||||
package com.foxinmy.weixin4j.base.test;
|
||||
|
||||
import org.apache.commons.httpclient.methods.GetMethod;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Proxy;
|
||||
import java.net.Proxy.Type;
|
||||
|
||||
import com.foxinmy.weixin4j.http.HttpClient;
|
||||
import com.foxinmy.weixin4j.http.HttpClientException;
|
||||
@ -11,11 +14,7 @@ import com.foxinmy.weixin4j.http.HttpResponse;
|
||||
import com.foxinmy.weixin4j.http.factory.HttpClientFactory;
|
||||
import com.foxinmy.weixin4j.http.factory.HttpComponent3Factory;
|
||||
import com.foxinmy.weixin4j.http.factory.HttpComponent4Factory;
|
||||
import com.foxinmy.weixin4j.http.factory.SimpleHttpClientFactory;
|
||||
import com.foxinmy.weixin4j.model.WeixinAccount;
|
||||
import com.foxinmy.weixin4j.token.FileTokenStorager;
|
||||
import com.foxinmy.weixin4j.token.TokenHolder;
|
||||
import com.foxinmy.weixin4j.util.Weixin4jConfigUtil;
|
||||
import com.foxinmy.weixin4j.util.IOUtil;
|
||||
|
||||
public class HttpClientTest {
|
||||
|
||||
@ -23,13 +22,12 @@ public class HttpClientTest {
|
||||
"https://www.baidu.com");
|
||||
static {
|
||||
HttpParams params = new HttpParams();
|
||||
//params.setProxy(new Proxy(Type.HTTP, new InetSocketAddress(
|
||||
// "218.92.227.170", 11095)));
|
||||
params.setProxy(new Proxy(Type.HTTP, new InetSocketAddress(
|
||||
"117.136.234.9", 80)));
|
||||
request.setParams(params);
|
||||
}
|
||||
|
||||
public static void test1() throws HttpClientException {
|
||||
HttpClientFactory.setDefaultFactory(new SimpleHttpClientFactory());
|
||||
HttpClient httpClient = HttpClientFactory.getInstance();
|
||||
HttpResponse response = httpClient.execute(request);
|
||||
print(response);
|
||||
@ -51,28 +49,23 @@ public class HttpClientTest {
|
||||
|
||||
public static void print(HttpResponse response) throws HttpClientException {
|
||||
System.err.println(response.getStatus());
|
||||
System.err.println(response.getBody());
|
||||
try {
|
||||
System.err.println(new String(
|
||||
IOUtil.toByteArray(response.getBody())));
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.err.println(response.getHeaders());
|
||||
System.err.println(response.getProtocol());
|
||||
}
|
||||
|
||||
public static void test() {
|
||||
org.apache.commons.httpclient.HttpClient hc = new org.apache.commons.httpclient.HttpClient();
|
||||
hc.getHostConfiguration().setProxy("127.0.0.1", 1080);
|
||||
org.apache.commons.httpclient.HttpMethod hm = new GetMethod(
|
||||
"http://www.baidu.com");
|
||||
try {
|
||||
hc.executeMethod(hm);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
//test1();
|
||||
test1();
|
||||
System.out.println("---------------------");
|
||||
//test2();
|
||||
// test2();
|
||||
System.out.println("---------------------");
|
||||
//test3();
|
||||
// test3();
|
||||
// test4();
|
||||
}
|
||||
}
|
||||
|
||||
@ -148,4 +148,8 @@
|
||||
|
||||
+ version upgrade to 1.5.3
|
||||
|
||||
+ 媒体接口类(MediaApi)查询素材接口调整:去掉offset,count替换为Pageable类
|
||||
+ 媒体接口类(MediaApi)查询素材接口调整:去掉offset,count替换为Pageable类
|
||||
|
||||
* 2015-09-08
|
||||
|
||||
+ 新增批量获取用户信息接口
|
||||
@ -1,5 +1,6 @@
|
||||
package com.foxinmy.weixin4j.mp.type;
|
||||
|
||||
|
||||
/**
|
||||
* 国家地区语言版本
|
||||
* @className Lang
|
||||
|
||||
@ -54,7 +54,7 @@ base on netty.
|
||||
}
|
||||
};
|
||||
// 当消息类型为文本(text)时回复「HelloWorld」, 否则回复调试消息
|
||||
new WeixinServerBootstrap(token,appid, aesKey).addHandler(
|
||||
new WeixinServerBootstrap(token, appid, aesKey).addHandler(
|
||||
messageHandler, DebugMessageHandler.global).startup();
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,7 +47,7 @@ public class ScanEventMessage extends EventMessage {
|
||||
}
|
||||
|
||||
public String getParameter() {
|
||||
return eventKey.replace("qrscene_", "");
|
||||
return eventKey.replaceFirst("qrscene_", "");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user