利用支付寶的團隊編寫的 HttpProtocolHandler 、StringRequestEntity 呼叫微信 支付引發的 body不是UTF8編碼的
阿新 • • 發佈:2019-02-05
HttpProtocolHandler 程式碼修改後的程式碼如下
修改過的程式碼:package com.whb.common.util.httpclient; import java.io.File; import java.io.IOException; import java.net.URLEncoder; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpConnectionManager; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; import org.apache.commons.httpclient.NameValuePair; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.StringRequestEntity; import org.apache.commons.httpclient.methods.multipart.FilePart; import org.apache.commons.httpclient.methods.multipart.FilePartSource; import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity; import org.apache.commons.httpclient.methods.multipart.Part; import org.apache.commons.httpclient.methods.multipart.StringPart; import org.apache.commons.httpclient.params.HttpMethodParams; import org.apache.commons.httpclient.util.IdleConnectionTimeoutThread; import org.apache.http.entity.StringEntity; import org.apache.log4j.Logger; import com.whb.common.util.Util; /* * *類名:HttpProtocolHandler *功能:HttpClient方式訪問 *詳細:獲取遠端HTTP資料 *版本:3.3 *日期:2012-08-17 *說明: *以下程式碼只是為了方便商戶測試而提供的樣例程式碼,商戶可以根據自己網站的需要,按照技術文件編寫,並非一定要使用該程式碼。 *該程式碼僅供學習和研究支付寶介面使用,只是提供一個參考。 */ public class HttpProtocolHandler { private static Logger log = Logger.getLogger(HttpProtocolHandler.class); private static String DEFAULT_CHARSET = "utf-8"; /** 連線超時時間,由bean factory設定,預設為8秒鐘 */ private int defaultConnectionTimeout = 8000; /** 迴應超時時間, 由bean factory設定,預設為30秒鐘 */ private int defaultSoTimeout = 30000; /** 閒置連線超時時間, 由bean factory設定,預設為60秒鐘 */ private int defaultIdleConnTimeout = 60000; private int defaultMaxConnPerHost = 30; private int defaultMaxTotalConn = 80; /** 預設等待HttpConnectionManager返回連線超時(只有在達到最大連線數時起作用):1秒*/ private static final long defaultHttpConnectionManagerTimeout = 3 * 1000; /** * HTTP連線管理器,該連線管理器必須是執行緒安全的. */ private HttpConnectionManager connectionManager; private static HttpProtocolHandler httpProtocolHandler = new HttpProtocolHandler(); /** * 工廠方法 * * @return */ public static HttpProtocolHandler getInstance() { return httpProtocolHandler; } /** * 私有的構造方法 */ private HttpProtocolHandler() { // 建立一個執行緒安全的HTTP連線池 connectionManager = new MultiThreadedHttpConnectionManager(); connectionManager.getParams().setDefaultMaxConnectionsPerHost(defaultMaxConnPerHost); connectionManager.getParams().setMaxTotalConnections(defaultMaxTotalConn); IdleConnectionTimeoutThread ict = new IdleConnectionTimeoutThread(); ict.addConnectionManager(connectionManager); ict.setConnectionTimeout(defaultIdleConnTimeout); ict.start(); } /** * 執行Http請求 * * @param request 請求資料 * @param strParaFileName 檔案型別的引數名 * @param strFilePath 檔案路徑 * @return * @throws HttpException, IOException */ public HttpResponse execute(HttpRequest request, String strParaFileName, String strFilePath) throws HttpException, IOException { HttpClient httpclient = new HttpClient(connectionManager); // 設定連線超時 int connectionTimeout = defaultConnectionTimeout; if (request.getConnectionTimeout() > 0) { connectionTimeout = request.getConnectionTimeout(); } httpclient.getHttpConnectionManager().getParams().setConnectionTimeout(connectionTimeout); // 設定迴應超時 int soTimeout = defaultSoTimeout; if (request.getTimeout() > 0) { soTimeout = request.getTimeout(); } httpclient.getHttpConnectionManager().getParams().setSoTimeout(soTimeout); // 設定等待ConnectionManager釋放connection的時間 httpclient.getParams().setConnectionManagerTimeout(defaultHttpConnectionManagerTimeout); String charset = request.getCharset(); charset = charset == null ? DEFAULT_CHARSET : charset; HttpMethod method = null; //get模式且不帶上傳檔案 if (request.getMethod().equals(HttpRequest.METHOD_GET)) { method = new GetMethod(request.getUrl()); method.getParams().setCredentialCharset(charset); // parseNotifyConfig會保證使用GET方法時,request一定使用QueryString method.setQueryString(request.getQueryString()); } else if(strParaFileName.equals("") && strFilePath.equals("")) { //post模式且不帶上傳檔案 method = new PostMethod(request.getUrl()); ((PostMethod) method).addParameters(request.getParameters()); method.addRequestHeader("Content-Type", "application/x-www-form-urlencoded; text/html; charset=" + charset); String body=request.getBody(); /** * 如果沒有這樣設定 預設編碼格式是 ISO-8859-1 向微信傳送請求會有問題 */ method.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, charset); if(!Util.isEmpty(body)) ((PostMethod) method).setRequestEntity(new StringRequestEntity(body,"text/html",charset)); } else { //post模式且帶上傳檔案 method = new PostMethod(request.getUrl()); List<Part> parts = new ArrayList<Part>(); for (int i = 0; i < request.getParameters().length; i++) { parts.add(new StringPart(request.getParameters()[i].getName(), request.getParameters()[i].getValue(), charset)); } //增加檔案引數,strParaFileName是引數名,使用本地檔案 parts.add(new FilePart(strParaFileName, new FilePartSource(new File(strFilePath)))); // 設定請求體 ((PostMethod) method).setRequestEntity(new MultipartRequestEntity(parts.toArray(new Part[0]), new HttpMethodParams())); } // 設定Http Header中的User-Agent屬性 method.addRequestHeader("User-Agent", "Mozilla/4.0"); HttpResponse response = new HttpResponse(); try { httpclient.executeMethod(method); if (request.getResultType().equals(HttpResultType.STRING)) { response.setStringResult(method.getResponseBodyAsString()); } else if (request.getResultType().equals(HttpResultType.BYTES)) { response.setByteResult(method.getResponseBody()); } response.setResponseHeaders(method.getResponseHeaders()); } catch (UnknownHostException ex) { return null; } catch (IOException ex) { return null; } catch (Exception ex) { return null; } finally { method.releaseConnection(); } return response; } /** * 將NameValuePairs陣列轉變為字串 * * @param nameValues * @return */ protected String toString(NameValuePair[] nameValues) { if (nameValues == null || nameValues.length == 0) { return "null"; } StringBuffer buffer = new StringBuffer(); for (int i = 0; i < nameValues.length; i++) { NameValuePair nameValue = nameValues[i]; if (i == 0) { buffer.append(nameValue.getName() + "=" + nameValue.getValue()); } else { buffer.append("&" + nameValue.getName() + "=" + nameValue.getValue()); } } return buffer.toString(); } }
原先不支援 Post for body 後來 我加了 如下 ,如下程式碼 會引發微信 支付引發的 body不是UTF8編碼的,但如果用Main傳送請求是正常的
method.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, charset); if(!Util.isEmpty(body)) ((PostMethod) method).setRequestEntity(new StringRequestEntity(body));
但對 StringRequestEntity 用的不多,後來修改如下:
method.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, charset);
if(!Util.isEmpty(body))
((PostMethod) method).setRequestEntity(new StringRequestEntity(body,"text/html",charset));