From 897e13958707361effb6f0724f71d6899f0b4e0e Mon Sep 17 00:00:00 2001 From: ecoolper Date: Thu, 20 Apr 2017 17:34:45 +0800 Subject: [PATCH] jodd --- .../http/jodd/ApacheHttpClientBuilder.java | 53 ++++ .../jodd/DefaultApacheHttpClientBuilder.java | 292 ++++++++++++++++++ .../http/jodd/InputStreamResponseHandler.java | 28 ++ .../jodd/MediaDownloadRequestExecutor.java | 76 +++++ .../http/jodd/MediaUploadRequestExecutor.java | 39 +++ .../util/http/jodd/RequestExecutor.java | 25 ++ .../http/jodd/SimpleGetRequestExecutor.java | 43 +++ .../http/jodd/SimplePostRequestExecutor.java | 51 +++ .../weixin/common/util/http/jodd/URIUtil.java | 48 +++ .../util/http/jodd/Utf8ResponseHandler.java | 33 ++ 10 files changed, 688 insertions(+) create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/ApacheHttpClientBuilder.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/DefaultApacheHttpClientBuilder.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/InputStreamResponseHandler.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaDownloadRequestExecutor.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaUploadRequestExecutor.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/RequestExecutor.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimpleGetRequestExecutor.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimplePostRequestExecutor.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/URIUtil.java create mode 100644 weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/Utf8ResponseHandler.java diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/ApacheHttpClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/ApacheHttpClientBuilder.java new file mode 100644 index 00000000..ce021a04 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/ApacheHttpClientBuilder.java @@ -0,0 +1,53 @@ +package me.chanjar.weixin.common.util.http.jodd; + +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.impl.client.CloseableHttpClient; + +/** + * httpclient build interface + * @author kakotor + */ +public interface ApacheHttpClientBuilder { + + /** + * 构建httpclient实例 + * + * @return new instance of CloseableHttpClient + */ + CloseableHttpClient build(); + + /** + * 代理服务器地址 + * + * @param httpProxyHost + */ + ApacheHttpClientBuilder httpProxyHost(String httpProxyHost); + + /** + * 代理服务器端口 + * + * @param httpProxyPort + */ + ApacheHttpClientBuilder httpProxyPort(int httpProxyPort); + + /** + * 代理服务器用户名 + * + * @param httpProxyUsername + */ + ApacheHttpClientBuilder httpProxyUsername(String httpProxyUsername); + + /** + * 代理服务器密码 + * + * @param httpProxyPassword + */ + ApacheHttpClientBuilder httpProxyPassword(String httpProxyPassword); + + /** + * ssl连接socket工厂 + * + * @param sslConnectionSocketFactory + */ + ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFactory sslConnectionSocketFactory); +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/DefaultApacheHttpClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/DefaultApacheHttpClientBuilder.java new file mode 100644 index 00000000..3f667abe --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/DefaultApacheHttpClientBuilder.java @@ -0,0 +1,292 @@ +package me.chanjar.weixin.common.util.http.jodd; + +import org.apache.commons.lang3.StringUtils; +import org.apache.http.annotation.NotThreadSafe; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.HttpRequestRetryHandler; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.config.SocketConfig; +import org.apache.http.conn.HttpClientConnectionManager; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.protocol.HttpContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * httpclient 连接管理器 + * + * @author kakotor + */ +@NotThreadSafe +public class DefaultApacheHttpClientBuilder implements ApacheHttpClientBuilder { + protected final Logger log = LoggerFactory.getLogger(DefaultApacheHttpClientBuilder.class); + private final AtomicBoolean prepared = new AtomicBoolean(false); + private int connectionRequestTimeout = 3000; + private int connectionTimeout = 5000; + private int soTimeout = 5000; + private int idleConnTimeout = 60000; + private int checkWaitTime = 60000; + private int maxConnPerHost = 10; + private int maxTotalConn = 50; + private String userAgent; + private HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() { + @Override + public boolean retryRequest(IOException exception, int executionCount, HttpContext context) { + return false; + } + }; + private SSLConnectionSocketFactory sslConnectionSocketFactory = SSLConnectionSocketFactory.getSocketFactory(); + private PlainConnectionSocketFactory plainConnectionSocketFactory = PlainConnectionSocketFactory.getSocketFactory(); + private String httpProxyHost; + private int httpProxyPort; + private String httpProxyUsername; + private String httpProxyPassword; + /** + * 闲置连接监控线程 + */ + private IdleConnectionMonitorThread idleConnectionMonitorThread; + private HttpClientBuilder httpClientBuilder; + + private DefaultApacheHttpClientBuilder() { + } + + public static DefaultApacheHttpClientBuilder get() { + return new DefaultApacheHttpClientBuilder(); + } + + @Override + public ApacheHttpClientBuilder httpProxyHost(String httpProxyHost) { + this.httpProxyHost = httpProxyHost; + return this; + } + + @Override + public ApacheHttpClientBuilder httpProxyPort(int httpProxyPort) { + this.httpProxyPort = httpProxyPort; + return this; + } + + @Override + public ApacheHttpClientBuilder httpProxyUsername(String httpProxyUsername) { + this.httpProxyUsername = httpProxyUsername; + return this; + } + + @Override + public ApacheHttpClientBuilder httpProxyPassword(String httpProxyPassword) { + this.httpProxyPassword = httpProxyPassword; + return this; + } + + @Override + public ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFactory sslConnectionSocketFactory) { + this.sslConnectionSocketFactory = sslConnectionSocketFactory; + return this; + } + + /** + * 获取链接的超时时间设置,默认3000ms + *

+ * 设置为零时不超时,一直等待. + * 设置为负数是使用系统默认设置(非上述的3000ms的默认值,而是httpclient的默认设置). + *

+ * + * @param connectionRequestTimeout 获取链接的超时时间设置(单位毫秒),默认3000ms + */ + public void setConnectionRequestTimeout(int connectionRequestTimeout) { + this.connectionRequestTimeout = connectionRequestTimeout; + } + + /** + * 建立链接的超时时间,默认为5000ms.由于是在链接池获取链接,此设置应该并不起什么作用 + *

+ * 设置为零时不超时,一直等待. + * 设置为负数是使用系统默认设置(非上述的5000ms的默认值,而是httpclient的默认设置). + *

+ * + * @param connectionTimeout 建立链接的超时时间设置(单位毫秒),默认5000ms + */ + public void setConnectionTimeout(int connectionTimeout) { + this.connectionTimeout = connectionTimeout; + } + + /** + * 默认NIO的socket超时设置,默认5000ms. + * + * @param soTimeout 默认NIO的socket超时设置,默认5000ms. + * @see java.net.SocketOptions#SO_TIMEOUT + */ + public void setSoTimeout(int soTimeout) { + this.soTimeout = soTimeout; + } + + /** + * 空闲链接的超时时间,默认60000ms. + *

+ * 超时的链接将在下一次空闲链接检查是被销毁 + *

+ * + * @param idleConnTimeout 空闲链接的超时时间,默认60000ms. + */ + public void setIdleConnTimeout(int idleConnTimeout) { + this.idleConnTimeout = idleConnTimeout; + } + + /** + * 检查空间链接的间隔周期,默认60000ms. + * + * @param checkWaitTime 检查空间链接的间隔周期,默认60000ms. + */ + public void setCheckWaitTime(int checkWaitTime) { + this.checkWaitTime = checkWaitTime; + } + + /** + * 每路的最大链接数,默认10 + * + * @param maxConnPerHost 每路的最大链接数,默认10 + */ + public void setMaxConnPerHost(int maxConnPerHost) { + this.maxConnPerHost = maxConnPerHost; + } + + /** + * 最大总连接数,默认50 + * + * @param maxTotalConn 最大总连接数,默认50 + */ + public void setMaxTotalConn(int maxTotalConn) { + this.maxTotalConn = maxTotalConn; + } + + /** + * 自定义httpclient的User Agent + * + * @param userAgent User Agent + */ + public void setUserAgent(String userAgent) { + this.userAgent = userAgent; + } + + public IdleConnectionMonitorThread getIdleConnectionMonitorThread() { + return this.idleConnectionMonitorThread; + } + + private synchronized void prepare() { + if(prepared.get()){ + return; + } + Registry registry = RegistryBuilder.create() + .register("http", this.plainConnectionSocketFactory) + .register("https", this.sslConnectionSocketFactory) + .build(); + + @SuppressWarnings("resource") + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry); + connectionManager.setMaxTotal(this.maxTotalConn); + connectionManager.setDefaultMaxPerRoute(this.maxConnPerHost); + connectionManager.setDefaultSocketConfig( + SocketConfig.copy(SocketConfig.DEFAULT) + .setSoTimeout(this.soTimeout) + .build() + ); + + this.idleConnectionMonitorThread = new IdleConnectionMonitorThread( + connectionManager, this.idleConnTimeout, this.checkWaitTime); + this.idleConnectionMonitorThread.setDaemon(true); + this.idleConnectionMonitorThread.start(); + + this.httpClientBuilder = HttpClients.custom() + .setConnectionManager(connectionManager) + .setConnectionManagerShared(true) + .setDefaultRequestConfig( + RequestConfig.custom() + .setSocketTimeout(this.soTimeout) + .setConnectTimeout(this.connectionTimeout) + .setConnectionRequestTimeout(this.connectionRequestTimeout) + .build() + ) + .setRetryHandler(this.httpRequestRetryHandler); + + if (StringUtils.isNotBlank(this.httpProxyHost) + && StringUtils.isNotBlank(this.httpProxyUsername)) { + // 使用代理服务器 需要用户认证的代理服务器 + CredentialsProvider provider = new BasicCredentialsProvider(); + provider.setCredentials( + new AuthScope(this.httpProxyHost, this.httpProxyPort), + new UsernamePasswordCredentials(this.httpProxyUsername, + this.httpProxyPassword)); + this.httpClientBuilder.setDefaultCredentialsProvider(provider); + } + + if (StringUtils.isNotBlank(this.userAgent)) { + this.httpClientBuilder.setUserAgent(this.userAgent); + } + prepared.set(true); + } + + @Override + public CloseableHttpClient build() { + if(!prepared.get()){ + prepare(); + } + return this.httpClientBuilder.build(); + } + + public static class IdleConnectionMonitorThread extends Thread { + private final HttpClientConnectionManager connMgr; + private final int idleConnTimeout; + private final int checkWaitTime; + private volatile boolean shutdown; + + public IdleConnectionMonitorThread(HttpClientConnectionManager connMgr, int idleConnTimeout, int checkWaitTime) { + super("IdleConnectionMonitorThread"); + this.connMgr = connMgr; + this.idleConnTimeout = idleConnTimeout; + this.checkWaitTime = checkWaitTime; + } + + @Override + public void run() { + try { + while (!this.shutdown) { + synchronized (this) { + wait(this.checkWaitTime); + this.connMgr.closeExpiredConnections(); + this.connMgr.closeIdleConnections(this.idleConnTimeout, + TimeUnit.MILLISECONDS); + } + } + } catch (InterruptedException ignore) { + } + } + + public void trigger() { + synchronized (this) { + notifyAll(); + } + } + + public void shutdown() { + this.shutdown = true; + synchronized (this) { + notifyAll(); + } + } + } +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/InputStreamResponseHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/InputStreamResponseHandler.java new file mode 100644 index 00000000..a766d4c2 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/InputStreamResponseHandler.java @@ -0,0 +1,28 @@ +package me.chanjar.weixin.common.util.http.jodd; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.StatusLine; +import org.apache.http.client.HttpResponseException; +import org.apache.http.client.ResponseHandler; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; +import java.io.InputStream; + +public class InputStreamResponseHandler implements ResponseHandler { + + public static final ResponseHandler INSTANCE = new InputStreamResponseHandler(); + + @Override + public InputStream handleResponse(final HttpResponse response) throws IOException { + final StatusLine statusLine = response.getStatusLine(); + final HttpEntity entity = response.getEntity(); + if (statusLine.getStatusCode() >= 300) { + EntityUtils.consume(entity); + throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase()); + } + return entity == null ? null : entity.getContent(); + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaDownloadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaDownloadRequestExecutor.java new file mode 100644 index 00000000..ff617e8e --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaDownloadRequestExecutor.java @@ -0,0 +1,76 @@ +package me.chanjar.weixin.common.util.http.jodd; + +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; +import me.chanjar.weixin.common.util.fs.FileUtils; +import org.apache.commons.lang3.StringUtils; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * 下载媒体文件请求执行器,请求的参数是String, 返回的结果是File + * 视频文件不支持下载 + * + * @author Daniel Qian + */ +public class MediaDownloadRequestExecutor implements RequestExecutor { + + private File tmpDirFile; + + public MediaDownloadRequestExecutor() { + } + + public MediaDownloadRequestExecutor(File tmpDirFile) { + this.tmpDirFile = tmpDirFile; + } + + @Override + public File execute(ProxyInfo httpProxy, String uri, String queryParam) throws WxErrorException, IOException { + if (queryParam != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") ? queryParam : '&' + queryParam; + } + + HttpRequest httpRequest = HttpRequest.post(uri); + HttpResponse response = httpRequest.send(); + String contentType = response.header("Content-Type"); + if (contentType != null && contentType.startsWith("application/json")) { + // application/json; encoding=utf-8 下载媒体文件出错 + throw new WxErrorException(WxError.fromJson(response.bodyText())); + } + + String fileName = getFileName(response); + if (StringUtils.isBlank(fileName)) { + return null; + } + + InputStream inputStream = new ByteArrayInputStream(response.bodyBytes()); + String[] nameAndExt = fileName.split("\\."); + return FileUtils.createTmpFile(inputStream, nameAndExt[0], nameAndExt[1], this.tmpDirFile); + } + + private String getFileName(HttpResponse response) throws WxErrorException { + String content = response.header("Content-disposition"); + if (content == null || content.length() == 0) { + throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); + } + + Pattern p = Pattern.compile(".*filename=\"(.*)\""); + Matcher m = p.matcher(content); + if (m.matches()) { + return m.group(1); + } + throw new WxErrorException(WxError.newBuilder().setErrorMsg("无法获取到文件名").build()); + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaUploadRequestExecutor.java new file mode 100644 index 00000000..43d7bbae --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/MediaUploadRequestExecutor.java @@ -0,0 +1,39 @@ +package me.chanjar.weixin.common.util.http.jodd; + +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import jodd.http.net.SocketHttpConnectionProvider; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; +import me.chanjar.weixin.common.exception.WxErrorException; + +import java.io.File; +import java.io.IOException; + +/** + * 上传媒体文件请求执行器,请求的参数是File, 返回的结果是String + * + * @author Daniel Qian + */ +public class MediaUploadRequestExecutor implements RequestExecutor { + + @Override + public WxMediaUploadResult execute(ProxyInfo httpProxy, String uri, File file) throws WxErrorException, IOException { + HttpRequest request = HttpRequest.post(uri); + if (httpProxy != null) { + SocketHttpConnectionProvider provider = new SocketHttpConnectionProvider(); + provider.useProxy(httpProxy); + request.withConnectionProvider(provider); + } + request.form("media", file); + HttpResponse response = request.send(); + String responseContent =response.bodyText(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return WxMediaUploadResult.fromJson(responseContent); + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/RequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/RequestExecutor.java new file mode 100644 index 00000000..ccc82702 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/RequestExecutor.java @@ -0,0 +1,25 @@ +package me.chanjar.weixin.common.util.http.jodd; + +import jodd.http.ProxyInfo; +import me.chanjar.weixin.common.exception.WxErrorException; + +import java.io.IOException; + +/** + * http请求执行器 + * + * @param 返回值类型 + * @param 请求参数类型 + */ +public interface RequestExecutor { + + /** + * @param httpProxy http代理对象,如果没有配置代理则为空 + * @param uri uri + * @param data 数据 + * @throws WxErrorException + * @throws IOException + */ + T execute(ProxyInfo httpProxy, String uri, E data) throws WxErrorException, IOException; + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimpleGetRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimpleGetRequestExecutor.java new file mode 100644 index 00000000..de84ad7b --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimpleGetRequestExecutor.java @@ -0,0 +1,43 @@ +package me.chanjar.weixin.common.util.http.jodd; + +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import jodd.http.net.SocketHttpConnectionProvider; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; + +import java.io.IOException; + +/** + * 简单的GET请求执行器,请求的参数是String, 返回的结果也是String + * + * @author Daniel Qian + */ +public class SimpleGetRequestExecutor implements RequestExecutor { + + @Override + public String execute(ProxyInfo httpProxy, String uri, String queryParam) throws WxErrorException, IOException { + if (queryParam != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") ? queryParam : '&' + queryParam; + } + + HttpRequest request = HttpRequest.get(uri); + if (httpProxy != null) { + SocketHttpConnectionProvider provider = new SocketHttpConnectionProvider(); + provider.useProxy(httpProxy); + request.withConnectionProvider(provider); + } + HttpResponse response = request.send(); + String responseContent = response.bodyText(); + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return responseContent; + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimplePostRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimplePostRequestExecutor.java new file mode 100644 index 00000000..276b1310 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/SimplePostRequestExecutor.java @@ -0,0 +1,51 @@ +package me.chanjar.weixin.common.util.http.jodd; + +import jodd.http.HttpRequest; +import jodd.http.HttpResponse; +import jodd.http.ProxyInfo; +import jodd.http.net.SocketHttpConnectionProvider; +import me.chanjar.weixin.common.bean.result.WxError; +import me.chanjar.weixin.common.exception.WxErrorException; + +import java.io.IOException; + +/** + * 简单的POST请求执行器,请求的参数是String, 返回的结果也是String + * + * @author Daniel Qian + */ +public class SimplePostRequestExecutor implements RequestExecutor { + + @Override + public String execute(ProxyInfo httpProxy, String uri, String postEntity) throws WxErrorException, IOException { + HttpRequest request = HttpRequest.post(uri); + if (httpProxy != null) { + SocketHttpConnectionProvider provider = new SocketHttpConnectionProvider(); + provider.useProxy(httpProxy); + request.withConnectionProvider(provider); + } + if (postEntity != null) { + request.bodyText(postEntity); + } + HttpResponse response = request.send(); + + String responseContent = response.bodyText(); + if (responseContent.isEmpty()) { + throw new WxErrorException( + WxError.newBuilder().setErrorCode(9999).setErrorMsg("无响应内容") + .build()); + } + + if (responseContent.startsWith("")) { + //xml格式输出直接返回 + return responseContent; + } + + WxError error = WxError.fromJson(responseContent); + if (error.getErrorCode() != 0) { + throw new WxErrorException(error); + } + return responseContent; + } + +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/URIUtil.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/URIUtil.java new file mode 100644 index 00000000..ac293d79 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/URIUtil.java @@ -0,0 +1,48 @@ +package me.chanjar.weixin.common.util.http.jodd; + + +import org.apache.commons.lang3.StringUtils; + +import java.io.UnsupportedEncodingException; + +public class URIUtil { + + private static final String ALLOWED_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.!~*'()"; + + public static String encodeURIComponent(String input) { + if (StringUtils.isEmpty(input)) { + return input; + } + + int l = input.length(); + StringBuilder o = new StringBuilder(l * 3); + try { + for (int i = 0; i < l; i++) { + String e = input.substring(i, i + 1); + if (ALLOWED_CHARS.indexOf(e) == -1) { + byte[] b = e.getBytes("utf-8"); + o.append(getHex(b)); + continue; + } + o.append(e); + } + return o.toString(); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + return input; + } + + private static String getHex(byte buf[]) { + StringBuilder o = new StringBuilder(buf.length * 3); + for (int i = 0; i < buf.length; i++) { + int n = buf[i] & 0xff; + o.append("%"); + if (n < 0x10) { + o.append("0"); + } + o.append(Long.toString(n, 16).toUpperCase()); + } + return o.toString(); + } +} diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/Utf8ResponseHandler.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/Utf8ResponseHandler.java new file mode 100644 index 00000000..e26d3e33 --- /dev/null +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/Utf8ResponseHandler.java @@ -0,0 +1,33 @@ +package me.chanjar.weixin.common.util.http.jodd; + +import org.apache.http.Consts; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.StatusLine; +import org.apache.http.client.HttpResponseException; +import org.apache.http.client.ResponseHandler; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; + +/** + * copy from {@link org.apache.http.impl.client.BasicResponseHandler} + * + * @author Daniel Qian + */ +public class Utf8ResponseHandler implements ResponseHandler { + + public static final ResponseHandler INSTANCE = new Utf8ResponseHandler(); + + @Override + public String handleResponse(final HttpResponse response) throws IOException { + final StatusLine statusLine = response.getStatusLine(); + final HttpEntity entity = response.getEntity(); + if (statusLine.getStatusCode() >= 300) { + EntityUtils.consume(entity); + throw new HttpResponseException(statusLine.getStatusCode(), statusLine.getReasonPhrase()); + } + return entity == null ? null : EntityUtils.toString(entity, Consts.UTF_8); + } + +}