zoukankan      html  css  js  c++  java
  • java模拟http/https post请求

    1.Post请求失败的代码

    try {
                 HttpResponse response = httpClient.execute(httpPost);
     
                 HttpEntity entity = response.getEntity();
     
                 result = EntityUtils.toString(entity, "UTF-8");
                 Util.log("API,POST回来的数据是:");
                 Util.log(result);
     
             } catch (ConnectionPoolTimeoutException e) {
                 log.e("http get throw ConnectionPoolTimeoutException(wait time out)");
     
             } catch (ConnectTimeoutException e) {
                 log.e("http get throw ConnectTimeoutException");
     
             } catch (SocketTimeoutException e) {
                 log.e("http get throw SocketTimeoutException");
     
             }  catch (Exception e) {
                 log.e("http get throw Exception");
     
             } finally {
                 httpPost.abort();
             }
    

    之前每次代码执行到上述代码的第二行的时候,会等一段时间然后会捕获到Exception异常。

    2.分析问题

    当然捕获的Exception这个异常太大了我们不便于分析,我们查看一下httpClient.execute(HttpUriRequest uri)的方法;

    发下这个方法会抛出IOException, ClientProtocolException这两个异常,但是在调用方法的时候并没有明确捕获他们两个。

    3.得出结论

    所以很有可能在执行post请求的过程中,遇到了这两个问题,果然我们把代码完善之后

    try {
                httpClient = new SSLClient();
                HttpResponse response = httpClient.execute(httpPost);
    
                HttpEntity entity = response.getEntity();
    
                result = EntityUtils.toString(entity, "UTF-8");
                Util.log("API,POST回来的数据是:");
                Util.log(result);
    
            } catch (ConnectionPoolTimeoutException e) {
                log.e("http get throw ConnectionPoolTimeoutException(wait time out)");
    
            } catch (ConnectTimeoutException e) {
                log.e("http get throw ConnectTimeoutException");
    
            } catch (SocketTimeoutException e) {
                log.e("http get throw SocketTimeoutException");
    
            } catch (ClientProtocolException e) {
                log.e("http get throw ClientProtocolException");
    
            } catch (IOException e) {
                e.printStackTrace();
    
            } catch (Exception e) {
                log.e("http get throw Exception");
    
            } finally {
                httpPost.abort();
            }

    上述,完善完毕代码后捕捉到了IOException异常,我们把异常打印出来看到了如下信息。

     4.解决问题

    通过在网上查询可知,这是缺少安全证书时出现的异常,解决方案如下:

    1. 等待Oracle/Google/Mozilla等等组织信任CNNIC,算了,洗洗睡吧
    2. 使用Java的TrustManager忽略所有的SSL请求的证书,仅仅用于开发测试,限于篇幅不做介绍了
    3. 导入目标网站的证书,然后在开始调用之前,指定keystore就ok了,本文介绍下该方法

    目前我们采用第二种方案:由于请求的URL是HTTPS的,为了避免需要证书,所以用一个类继承DefaultHttpClient类,忽略校验过程。

    编写一个SSLClient类

    package com.phicomm.smarthome.sharedwifi.util;
    
    import java.security.cert.CertificateException;
    import java.security.cert.X509Certificate;
    
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.TrustManager;
    import javax.net.ssl.X509TrustManager;
    
    import org.apache.http.conn.ClientConnectionManager;
    import org.apache.http.conn.scheme.Scheme;
    import org.apache.http.conn.scheme.SchemeRegistry;
    import org.apache.http.conn.ssl.SSLSocketFactory;
    import org.apache.http.impl.client.DefaultHttpClient;
    
    public class SSLClient extends DefaultHttpClient {
    
        public SSLClient() throws Exception {
            super();
            SSLContext ctx = SSLContext.getInstance("TLS");
            X509TrustManager tm = new X509TrustManager() {
    
                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    // TODO Auto-generated method stub
    
                }
    
                @Override
                public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    // TODO Auto-generated method stub
    
                }
    
                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    // TODO Auto-generated method stub
                    return null;
                }
            };
            ctx.init(null, new TrustManager[] { tm }, null);
            SSLSocketFactory ssf = new SSLSocketFactory(ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            ClientConnectionManager ccm = this.getConnectionManager();
            SchemeRegistry sr = ccm.getSchemeRegistry();
            sr.register(new Scheme("https", 443, ssf));
        }
    }

     对应的实现类:

    public HttpResponse sendPostToService(String url, Object pushData) throws IOException, KeyStoreException,
                UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException {
    
            if (!hasInit) {
                init();
            }
    
            String result = null;
    
            HttpPost httpPost = new HttpPost(url);
    
            StringEntity postEntity = new StringEntity(pushData.toString(),
                    ContentType.create("application/x-www-form-urlencoded", "UTF-8"));
            // 设置一些Http头信息
            httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded");
            httpPost.addHeader("connection", "Keep-Alive");
            httpPost.addHeader("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            // 将发送内容填装
            httpPost.setEntity(postEntity);
    
            // 设置请求器的配置
            httpPost.setConfig(requestConfig);
    
            // 打印待发送的数据
            Util.log("=====API,POST过去的数据是:");
            Util.log("executing request" + httpPost.getRequestLine());
            Util.log("请求头信息===" + httpPost.getAllHeaders().toString());
            Util.log("请求状态行===" + httpPost.getRequestLine());
            Util.log("请求配置===" + httpPost.getConfig());
            Util.log("请求实体===" + httpPost.getEntity().getContentEncoding() + httpPost.getEntity().getContentType()
                    + httpPost.getEntity().getContent());
    
            HttpResponse response = null;
            try {
                // 忽略所有的SSL请求的证书
                httpClient = new SSLClient();
                response = httpClient.execute(httpPost);
    
                HttpEntity entity = response.getEntity();
    
                result = EntityUtils.toString(entity, "UTF-8");
                // 打印得到的响应信息
                Util.log("API,POST回来的数据是:");
                Util.log("=====Entity:" + result);
                Util.log("=====Headers:" + response.getAllHeaders());
                Util.log("=====StatusLine:" + response.getStatusLine());
                Util.log("=====Locale:" + response.getLocale());
    
            } catch (ConnectionPoolTimeoutException e) {
                log.e("http get throw ConnectionPoolTimeoutException(wait time out)");
    
            } catch (ConnectTimeoutException e) {
                log.e("http get throw ConnectTimeoutException");
    
            } catch (SocketTimeoutException e) {
                log.e("http get throw SocketTimeoutException");
    
            } catch (ClientProtocolException e) {
                log.e("http get throw ClientProtocolException");
    
            } catch (IOException e) {
                e.printStackTrace();
    
            } catch (Exception e) {
                log.e("http get throw Exception");
    
            } finally {
                httpPost.abort();
            }
    
            return response;
        }

    在第36行使用自定义的SSLClient来忽略掉验证要求

    另外注意在postMan中模拟调用的时候我们是用的x-www-form-urlencoded格式的数据请求,就是application/x-www-from-urlencoded,会将表单内的数据转换为键值对。

    当action为get时候,浏览器用x-www-form-urlencoded的编码方式把form数据转换成一个字串(name1=value1&name2=value2...),然后把这个字串append到url后面,用?分割,加载这个新的url。 当action为post时候,浏览器把form数据封装到http body中,然后发送到server。 

    所以我们需要对传进来的数据做一下处理:

    // 拼接x-www-form-urlencoded格式的请求参数
            String www_url = "coverimg=" + pushMsgModel.getCoverimg() + "&mode=" + pushMsgModel.getMode() + "&msgcontent="
                    + pushMsgModel.getMsgContent() + "&msgtype=" + pushMsgModel.getMsgtype() + "&outline="
                    + pushMsgModel.getOutline() + "&saveRecord=" + pushMsgModel.getSaveRecord() + "&source="
                    + pushMsgModel.getSource() + "&ticker=" + pushMsgModel.getTicker() + "&timestamp="
                    + pushMsgModel.getTimestamp() + "&title=" + pushMsgModel.getTitle() + "&uid=" + pushMsgModel.getUid()
                    + "&url=" + pushMsgModel.getUrl();
            logger.info("x-www-form-urlencoded格式的请求参数为:" + www_url);

    最后效果如下:

  • 相关阅读:
    动态加载方法(定时任务)
    安装 asp.net core 出错
    .NET:权限管理
    关于随机数
    博客园首弹
    C# MVC从其他系统获取文件流,显示文件
    Python中操作MySQL步骤
    MySql之_增删改查
    数据库之_SQL注入
    为什么上传到youtube上的视频很模糊
  • 原文地址:https://www.cnblogs.com/lingyejun/p/7418268.html
Copyright © 2011-2022 走看看