首页 > 代码库 > httpclient

httpclient

最近碰到一个问题,拖了好几天还没个具体的坚决方案。在此记录一下:

 

java客户端调用服务端的http接口,按理说应该是个很简单的事情。直接用httpclient

以下是get请求

public  static String getHttp(String url) {
        String responseMsg = "";
        
        // 1.构造HttpClient的实例
        HttpClient httpClient = new HttpClient();
        // 用于测试的http接口的url
        //url = url+"?agentid "+agentid+"idcard=" + idcard+ "&sign=" + sign;
        // 2.创建GetMethod的实例
        GetMethod getMethod = new GetMethod(url);
        // 使用系统系统的默认的恢复策略
        getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
                new DefaultHttpMethodRetryHandler());

        try {
            // 3.执行getMethod,调用http接口
            int resultCode = httpClient.executeMethod(getMethod);
            System.out.println("身份证校验接口返回码:"+resultCode);
            if(resultCode!= 200){
                return "接口返回失败";
            }
            // 4.读取内容
            byte[] responseBody = getMethod.getResponseBody();
            // 5.处理返回的内容
            responseMsg = new String(responseBody);
            System.out.println(responseMsg);

        } catch (HttpException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 6.释放连接
            getMethod.releaseConnection();
        }
        return responseMsg;
    }

 

post请求

/**
     * POST请求
     * @param param
     * @return
     */
    public static String postHttp(String [] param) {
        String responseMsg = "";
        // 1.构造HttpClient的实例
        HttpClient httpClient = new HttpClient();
        //链接超时,毫秒
        httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(30000);  
        //读取超时
        httpClient.getHttpConnectionManager().getParams().setSoTimeout(30000);
        
        httpClient.getParams().setContentCharset("UTF-8");
        //String url = "http://www.baidu.com";
        // 2.构造PostMethod的实例
        PostMethod postMethod = new PostMethod(param[0]);
        // 3.把参数值放入到PostMethod对象中
        // 方式1:
        NameValuePair[] data = http://www.mamicode.com/{
                new NameValuePair("agentid", param[1]),
                new NameValuePair("operate_type", param[2]),
                new NameValuePair("merchantid", param[3]),
                new NameValuePair("pinpad_uuid", param[4]),
                  new NameValuePair("sign", param[5])
        };
        postMethod.setRequestBody(data);
        
        try {
            // 4.执行postMethod,调用http接口
            int returnCode;
            try {
                returnCode = httpClient.executeMethod(postMethod);
                System.out.println("终端接口返回码:"+returnCode);
                if(returnCode!=200){
                    return "审核失败,接口返回code:"+returnCode;
                }
            } catch (java.net.SocketTimeoutException e) {
                e.printStackTrace();
                return "接口返回超时";
            }
            
            // 5.读取内容
            responseMsg = postMethod.getResponseBodyAsString().trim();
            System.out.println(responseMsg);
            // 6.处理返回的内容
            //TODO:接口还未通,待查看返回数据调试

        } catch (HttpException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 7.释放连接
            postMethod.releaseConnection();
        }
        return responseMsg;
    }
    
    以上两段最简单不过了。测试可用··直接本地写了上测试环境,通过然后上准生产环境。一切顺利通过,正式部署到生产环境,然后问题来了。纠结了好几天。post请求调用服务端接口第一天还正常的,第二天来平台使用客户说点了功能按钮没反应!立马查看日志····查看问题。还真是点了没反应

    returnCode = httpClient.executeMethod(postMethod);
                System.out.println("终端接口返回码:"+returnCode);

查看日志代码走到这一步就停住了。收不到返回码。之前还没有加上超时设置所以也不报错,点了没反应。后来才设置的超时时间30秒,收不到答复报出异常。然后联系服务端帮忙一起查看问题,结果是对方说接口有返回的。然后我说我这里收不到。这之间各种沟通,然后网络抓包。说他们有返回,我们收不到可能是我们程序问题或者网络问题。可有时候调用接口又是正常的。所以为什么有时可以,有时又不行呢。一个功能按钮,成了搏概率事件。

   作为码农,我怎么能让程序有问题。各种检查,各种改。怀疑httpclient版本,用的3.1,现在有4.0,也提出可能是网络问题。然后老大出面找网络层的帮忙看问题。最后说是网络抓包也能收到对方给的应答,会不是是我的程序有问题。然后又改,加httpclient绑定ip地址发送请求。这里先说一下,我们生产机器是双网卡,所以一度怀疑是网卡问题。我只能保证程序肯定是没问题的。但问题总得解决,虽然我搞不定。但一直拖着没解决总是不爽。

tcpdump -i eth6 -Xxven host 113.98.254.173 -w pos.pacp  抓包文件查看。

以下为结论:
服务端应答包在底层会分成两个Fragment(估计是因为MTU限制)。出错时,第2个Fragment的TCP checksum错误,因此导致通贝系统这里认为这个Fragment错误,丢弃,从而应用层无法收到返回信息。TCP层也不给ACK。而能成功收到应答时,服务端给出的TCP包的Checksum就是对的。可能是系统网卡不稳定,通常现在的TCP都会offload,通过网卡来做发送包的checksum,然后B端说不能动服务器叫我们关掉网卡网卡的这个功能(收包部分)再抓包看看,或者在防火墙或者交换机抓就知道是否正确了.
TCP报文在OFFload过程被硬件重组了.然后我们只好又等到晚上拔掉网卡,重新抓包。
 
 
1、已经关闭我网卡上的offload,问题照旧,B端发过来的包的checksum还是存在部分错误,导致信息被我们接收到。
2、我们从路由器上抓包,也验证了源地址为113.98.254.173过来的包checksum是错的





httpclient