使用Java原生API编写发送HTTP_POST请求的工具类

来源:互联网 发布:剑三捏脸数据成男下载 编辑:程序博客网 时间:2024/05/18 00:17
    1. package com.jadyer.util;  
    2.   
    3. import java.io.ByteArrayOutputStream;  
    4. import java.io.InputStream;  
    5. import java.io.OutputStream;  
    6. import java.io.UnsupportedEncodingException;  
    7. import java.net.HttpURLConnection;  
    8. import java.net.URL;  
    9. import java.net.URLEncoder;  
    10. import java.util.HashMap;  
    11. import java.util.List;  
    12. import java.util.Map;  
    13.   
    14. /** 
    15.  * 使用Java原生API编写发送HTTP_POST请求的工具类 
    16.  * @see ------------------------------------------------------------------------------------------ 
    17.  * @see 与之类似的还有一个HttpClientUtil工具类 
    18.  * @see 地址为http://blog.csdn.net/jadyer/article/details/8087960 
    19.  * @see ------------------------------------------------------------------------------------------ 
    20.  * @see 本方法的美中不足是:服务器返回500时,它会直接抛出类似下面的异常 
    21.  * @see java.io.IOException: Server returned HTTP response code: 500 for URL: http://xxxx/xxxx 
    22.  * @see 原因很简单:因为这里用到的是SUN提供的基于HTTP协议的框架实现 
    23.  * @see ------------------------------------------------------------------------------------------ 
    24.  * @see 个人更推荐使用Socket发送HTTP请求 
    25.  * @see 例子见http://blog.csdn.net/jadyer/article/details/8788272 
    26.  * @see ------------------------------------------------------------------------------------------ 
    27.  * @create Mar 4, 2013 2:47:57 PM 
    28.  * @editor Apr 4, 2013 10:02:18 AM 
    29.  * @author 玄玉<http://blog.csdn.net/jadyer> 
    30.  */  
    31. public class NativeHTTPUtil {  
    32.     private NativeHTTPUtil(){}  
    33.       
    34.     /** 
    35.      * 发送HTTP_POST请求 
    36.      * @see 本方法默认的连接和读取超时均为30秒 
    37.      * @see 请求参数含有中文时,亦可直接传入本方法中,本方法内部会自动根据reqCharset参数进行<code>URLEncoder.encode()</code> 
    38.      * @see 解码响应正文时,默认取响应头[Content-Type=text/html; charset=GBK]字符集,若无Content-Type,则使用UTF-8解码 
    39.      * @param reqURL     请求地址 
    40.      * @param reqParams  请求正文数据 
    41.      * @param reqCharset 请求报文的编码字符集(主要针对请求参数值含中文而言) 
    42.      * @return respCode-->HTTP响应码,respBody-->HTTP响应报文体,respMsg-->HTTP响应完整报文 
    43.      */  
    44.     public static Map<String, String> sendPostRequest(String reqURL, Map<String, String> reqParams, String reqCharset) {  
    45.         StringBuilder reqData = new StringBuilder();  
    46.         for (Map.Entry<String, String> entry : reqParams.entrySet()) {  
    47.             try {  
    48.                 reqData.append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue(), reqCharset)).append("&");  
    49.             } catch (UnsupportedEncodingException e) {  
    50.                 System.out.println("编码字符串[" + entry.getValue() + "]时发生异常:系统不支持该字符集[" + reqCharset + "]");  
    51.                 reqData.append(entry.getKey()).append("=").append(entry.getValue()).append("&");  
    52.             }  
    53.         }  
    54.         if (reqData.length() > 0) {  
    55.             reqData.setLength(reqData.length() - 1); //删除最后一个&符号  
    56.         }  
    57.         return sendPostRequest(reqURL, reqData.toString(), reqCharset);  
    58.     }  
    59.       
    60.       
    61.     /** 
    62.      * 发送HTTP_POST请求 
    63.      * @see you can see {@link NativeHTTPUtil#sendPostRequest(String, Map, String)} 
    64.      * @see 注意:若欲直接调用本方法,切记请求参数值含中文时,一定要对该参数值<code>URLEncoder.encode(value, reqCharset)</code> 
    65.      * @see 注意:这里只是对key=value中的'value'进行encode,而非'key='..encode完毕后,再组织成key=newValue传给本方法 
    66.      */  
    67.     public static Map<String, String> sendPostRequest(String reqURL, String reqData, String reqCharset) {  
    68.         Map<String, String> respMap = new HashMap<String, String>();  
    69.         HttpURLConnection httpURLConnection = null;  
    70.         OutputStream out = null//写  
    71.         InputStream in = null;   //读  
    72.         String respBody = null;  //HTTP响应报文体  
    73.         String respCharset = "UTF-8";  
    74.         try {  
    75.             URL sendUrl = new URL(reqURL);  
    76.             httpURLConnection = (HttpURLConnection)sendUrl.openConnection();  
    77.             httpURLConnection.setDoInput(true);    //true表示允许获得输入流,读取服务器响应的数据,该属性默认值为true  
    78.             httpURLConnection.setDoOutput(true);   //true表示允许获得输出流,向远程服务器发送数据,该属性默认值为false  
    79.             httpURLConnection.setUseCaches(false); //禁止缓存  
    80.             httpURLConnection.setReadTimeout(30000);    //30秒读取超时  
    81.             httpURLConnection.setConnectTimeout(30000); //30秒连接超时  
    82.             httpURLConnection.setRequestMethod("POST");  
    83.               
    84.             out = httpURLConnection.getOutputStream();  
    85.             out.write(reqData.getBytes());  
    86.             out.flush(); //发送数据  
    87.               
    88.             /** 
    89.              * 获取HTTP响应头 
    90.              * @see URLConnection类提供了读取远程服务器响应数据的一系列方法 
    91.              * @see getHeaderField(String name)可以返回响应头中参数name指定的属性的值 
    92.              * @see 注意:经过我的测试,此处获取到头属性的顺序与服务器响应的真实头属性顺序或可不一致 
    93.              * @see 注意:测试时,我让服务器返回的头属性中,Content-Type排在第一个,Content-Length排在第二个 
    94.              * @see 注意:结果在此处获取到的响应头属性中,Content-Length排在第一个,Content-Type排在第二个 
    95.              */  
    96.             StringBuilder respHeader = new StringBuilder();  
    97.             Map<String, List<String>> headerFields = httpURLConnection.getHeaderFields();  
    98.             for(Map.Entry<String, List<String>> entry : headerFields.entrySet()){  
    99.                 StringBuilder sb = new StringBuilder();  
    100.                 for(int i=0; i<entry.getValue().size(); i++){  
    101.                     sb.append(entry.getValue().get(i));  
    102.                 }  
    103.                 if(null == entry.getKey()){  
    104.                     respHeader.append(sb.toString());  
    105.                 }else{  
    106.                     respHeader.append(entry.getKey()).append(": ").append(sb.toString());  
    107.                 }  
    108.                 respHeader.append("\r\n");  
    109.             }  
    110.               
    111.             /** 
    112.              * 获取Content-Type中的charset值 
    113.              * @see 如Content-Type: text/html; charset=GBK 
    114.              */  
    115.             String contentType = httpURLConnection.getContentType();  
    116.             if(null!=contentType && contentType.toLowerCase().contains("charset")){  
    117.                 respCharset = contentType.substring(contentType.lastIndexOf("=") + 1);  
    118.             }  
    119.               
    120.             /** 
    121.              * 获取HTTP响应正文 
    122.              * @see --------------------------------------------------------------------------------------------- 
    123.              * @see SUN提供了基于HTTP协议的框架实现,不过,这些实现类并没有在JDK类库中公开,它们都位于sun.net.www包或者其子包中 
    124.              * @see 并且,URLConnection具体子类(HttpURLConnection类)的getInputStream()方法仅仅返回响应正文部分的输入流 
    125.              * @see HTTP响应结果包括HTTP响应码,响应头和响应正文3部分,获得输入流后,就能读取服务器发送的响应正文 
    126.              * @see ---------------------------------------------------------------------------------------------- 
    127.              * @see 使用httpURLConnection.getContentLength()时,要保证服务器给返回Content-Length头属性 
    128.              * @see byte[] byteDatas = new byte[httpURLConnection.getContentLength()]; 
    129.              * @see httpURLConnection.getInputStream().read(byteDatas); 
    130.              * @see respBody = new String(byteDatas, respCharset); 
    131.              * @see ---------------------------------------------------------------------------------------------- 
    132.              * @see in = httpURLConnection.getInputStream(); 
    133.              * @see byte[] byteDatas = new byte[in.available()]; 
    134.              * @see 关于InputStream.available()说明如下,更详细说明见JDK API DOC 
    135.              * @see 有些InputStream的实现将返回流中的字节总数,但也有很多实现不会这样做 
    136.              * @see 试图使用in.available()方法的返回值分配缓冲区,以保存此流所有数据的做法是不正确的 
    137.              * @see ---------------------------------------------------------------------------------------------- 
    138.              */  
    139.             in = httpURLConnection.getInputStream();  
    140.             ByteArrayOutputStream buffer = new ByteArrayOutputStream();  
    141.             byte[] buff = new byte[1024];  
    142.             int len = -1;  
    143.             while((len=in.read(buff)) != -1){  
    144.                 buffer.write(buff, 0, len);  
    145.             }  
    146.             respBody = buffer.toString(respCharset);  
    147.               
    148.             //使用httpURLConnection.getResponseMessage()可以获取到[HTTP/1.0 200 OK]中的[OK]  
    149.             respMap.put("respCode", String.valueOf(httpURLConnection.getResponseCode()));  
    150.             respMap.put("respBody", respBody);  
    151.             respMap.put("respMsg", respHeader.toString() + "\r\n" + respBody);  
    152.             return respMap;  
    153.         } catch (Exception e) {  
    154.             System.out.println("与[" + reqURL + "]通信异常,堆栈信息如下");  
    155.             e.printStackTrace();  
    156.             return respMap;  
    157.         } finally {  
    158.             if (out != null) {  
    159.                 try {  
    160.                     out.close();  
    161.                 } catch (Exception e) {  
    162.                     System.out.println("关闭输出流时发生异常,堆栈信息如下");  
    163.                     e.printStackTrace();  
    164.                 }  
    165.             }  
    166.             if (in != null) {  
    167.                 try {  
    168.                     in.close();  
    169.                 } catch (Exception e) {  
    170.                     System.out.println("关闭输入流时发生异常,堆栈信息如下");  
    171.                     e.printStackTrace();  
    172.                 }  
    173.             }  
    174.             if (httpURLConnection != null) {  
    175.                 httpURLConnection.disconnect();  
    176.                 httpURLConnection = null;  
    177.             }  
    178.         }  
    179.     }  
    180. }  


    下面是测试代码

    [java] view plain copy
     print?
    1. public static void main(String[] args) {  
    2.     Map<String, String> params = new HashMap<String, String>();  
    3.     params.put("merNo""301100100001630");  
    4.     params.put("signType""MD5");  
    5.     params.put("merBindAgrNo""00003018007000006450000013866742");  
    6.     params.put("interfaceVersion""1.0.0.0");  
    7.     params.put("amount""1000");  
    8.     params.put("orderDate""20120823");  
    9.     params.put("orderNo""UDP1208230917531231111");  
    10.     params.put("merReqTime""20120823091802");  
    11.     params.put("goodsDesc""为号码交费充值元");  
    12.     params.put("goodsName""中国联通交费充值");  
    13.     params.put("userIdeMark""3");  
    14.     params.put("bankAgrMode""9");  
    15.     params.put("signMsg""3ced24a118461043901d47815e6905a8");  
    16.     Map<String, String> respMap = sendPostRequest("http://127.0.0.1/tra/bind/payment.htm", params, "UTF-8");  
    17.     System.out.println("=============================================================================");  
    18.     System.out.println("HTT响应码如下");  
    19.     System.out.println(respMap.get("respCode"));  
    20.     System.out.println("=============================================================================");  
    21.     System.out.println("HTT响应正文如下");  
    22.     System.out.println(respMap.get("respBody"));  
    23.     System.out.println("=============================================================================");  
    24.     System.out.println("HTTP响应完整报文如下");  
    25.     System.out.println(respMap.get("respMsg"));  
    26.     System.out.println("=============================================================================");  
    27. }  

    下面是控制台输出

    [java] view plain copy
     print?
    1. //控制台输出如下  
    2. //=============================================================================  
    3. //  HTT响应码如下  
    4. //  200  
    5. //  =============================================================================  
    6. //  HTT响应正文如下  
    7. //  interfaceVersion=1.0.0.0  
    8. //  merReqTime=  
    9. //  payJournl=  
    10. //  amount=  
    11. //  orderNo=UDP1208230917531231111  
    12. //  orderTime=20120823  
    13. //  payBankNo=  
    14. //  bankAccNo=  
    15. //  bankAccName=  
    16. //  transRet=ILLEGAL_MERCHANT_NO  
    17. //  resultDis=商户签名key查询失败致使无法验签  
    18. //  acceptDate=  
    19. //  acceptTime=  
    20. //  signType=MD5  
    21. //  signMsg=29a312ab08b7273d7500a960c8c86b73  
    22. //  =============================================================================  
    23. //  HTTP响应完整报文如下  
    24. //  HTTP/1.1 200 OK  
    25. //  Content-Length: 289  
    26. //  Content-Type: text/html; charset=GBK  
    27. //  
    28. //  interfaceVersion=1.0.0.0  
    29. //  merReqTime=  
    30. //  payJournl=  
    31. //  amount=  
    32. //  orderNo=UDP1208230917531231111  
    33. //  orderTime=20120823  
    34. //  payBankNo=  
    35. //  bankAccNo=  
    36. //  bankAccName=  
    37. //  transRet=ILLEGAL_MERCHANT_NO  
    38. //  resultDis=商户签名key查询失败致使无法验签  
    39. //  acceptDate=  
    40. //  acceptTime=  
    41. //  signType=MD5  
    42. //  signMsg=29a312ab08b7273d7500a960c8c86b73  
    43. //  =============================================================================  
    44. //  
0 0
原创粉丝点击