在使用 HttpClient 4.4 调用第三方 http api 时遇到了很多问题,还好最后都解决了,记录一下遇到的问题及解决办法,希望对同样有此问题的你有所帮助。

环境说明

首先说明一点是,对方的测试环境是在公共的网络环境下部署的,即是对外开放的,需用外网访问,不支持内网,只支持走专线(目前不考虑这个方式,因为铺设专线耗时还耗经费)。

所以在调试接口的时候就直接在个人笔记本上使用 POSTMAN 这样的接口调试工具进行调试。

在微信群里和第三方联调,对方告诉我们需要调用哪几支接口,然后我们就按照接口文档去调试了。

调试的过程中发现了很多的问题。例如,对方并没有口头或文档说明需要传APPID、APPKEY和一些其他参数,这些参数是放在Head头部的,三方没有提前告诉我们需要这些参数,我们在联调时发现接口报异常【APPID 不能为空】,然后就把这个问题发到群里,半天才回复,而且是他们内部互相踢皮球,搞了半天才确定谁去解决。

不就是在系统里创建一个appid和密钥嘛,结果第二天下午才给搞好。这效率真是没法说,而且我觉得既然跟我们合作(我们是强势方),你就把需要的东西都准备好了,有啥问题积极回答、解决,这样效率也高。

这个问题解决了,需要调的接口通过 POSTMAN 很快就都调试了一遍,没啥大问题都正常通过联调,接下来就是通过代码调用了,还有处理一些细节的东西。

解决文件上传发送multipart/form-data请求

由于对方测试环境是部署在外网,我们公司的开发环境是在公司的内网,而且必须在公司的内网里开发(不然连不上数据库项目启动不了),这个问题是没办法解决的,所以就干脆先在自己的笔记本电脑上把代码写完,再传到公司开发机上。

刚开始打算使用 Java 自带的 java.net.HttpURLConnection 那一套方式,但是调第二个接口时发现需要上传文件,content-type需要为 multipart/form-data。

如果还继续使用 java.net 包下的那一套就会非常麻烦,因为上传文件和普通参数不一样,需要有分割符来分割文件以及普通参数,因为服务端需要知道文件从哪开始到哪结束。

这些工作需要客户端程序来处理,如果还继续用java.net包下的类,将会使此工作开发起来很麻烦,所以最后选择使用 HttpClient 工具包来处理这个问题。

HttpClient 是 Apache 软件基金会下的开源项目,是目前较流行和好用的 http 网络请求工具包,遵循Java面向对象编程的原则。。。关于 HttpClient 就不多说了,想了解的自行百度下。

HttpClient封装了发送 multipart/form-data 类型的请求的实现细节,具体使用方法见这篇文章

在 HttpClient 的帮助下,基本代码已经写完且相关接口都已经通过代码的方式调通了。

解决代理及 400 Bad request

于是便把代码上传至公司的开发机,准备完善一些细节处理。

等这些工作都做完时,委托同事开通的代理服务器到第三方IP的网络策略也都已经搞完(开发机、测试环境都是内网环境,不能直连互联网,故需通过代理服务器来访问目标地址,到时候线上也一样。我们的开发机访问不了代理服务器,所以只能在测试环境测)。

把代码提交后部署到测试环境后,我已经迫不及待的想要测试一下了。这是第一次测试这个功能,我记得是失败了,报错,400 Bad request。这是什么问题?参看这篇,但是网上说的最多的两种情况,都和我的不符,所以在这篇文章也找到了解决办法。

因为我测试环境走的代理,在自己笔记本联调时是互联网直连的,所以没有此问题。通过查看代码,我发现我设置代理的时候用的默认的 HTTP 协议,而我要访问的目标地址是 HTTPS 的,所以我怀疑是这的问题。于是我就把目标地址改为HTTP 方法请求(对方也支持HTTP),果然好了。但这样又引发了其他问题,且看下面。

解决 502 Bad Getway 

接下来的很多次,再去测试的时候,发现很多时候都是报超时,Read timeout, 因为我设置的等待响应的时间是10秒。我把这个设置去掉之后,大概等30秒,返回的错误是 502 Bad Getway

502 Bad Gateway是指错误网关,无效网关;在互联网中表示一种网络错误。表现在WEB浏览器中给出的页面反馈。
含义:这通常并不意味着上游服务器已关闭(无响应网关/代理) ,而是上游服务器和网关/代理使用不一致的协议交换数据。鉴于互联网协议是相当清楚的,它往往意味着一个或两个机器已不正确或不完全编程。

这是什么错?无从下手啊。

想着是不是还是协议不一致导致的?于是我又把协议这方面的 http 对 https ,这样互相排列组合的改了几次还是不行。

然后我就在网上搜这个问题咋解决,无意中在一个国外的网站行看到有人问这个问题咋解决

其中一个回复说【您可能正在使用代理来获取ssl内容,但您的代理设置是错误的。您应该考虑使用http作为代理方案,然后使用https作为实际内容的方案。这解决了我的问题】

说的好准,确实使用了代理。

解决证书问题-javax.net.ssl.SSLException:Unrecognized SSL message,plaintext connection?

于是把代理又改成 HTTP 的,然后又抛异常:jvax.net.ssl.SSLException:Unrecognized SSL message,plaintext connection?

查了一下意思是说,无法识别 SSL 信息,明文连接?原来是证书方面的问题,要加一下代码,使其信任所有证书,具体怎么加看这篇

然后按这篇文章加了信任所有证书就好了。

总结

之前对 Http 接口不是太了解,基本上没怎么用过,通过这次认识到了自己在这方面的知识很欠缺,要好好补一补了。https://www.cnblogs.com/ibigboy/p/11251152.html