今天来聊聊我捣鼓 `*` 的那点事儿。说起来也是好几年前,那时候接手一个老项目,需要跟一个外部的接口打交道,就是那种提供数据的 веб-сервис。当时项目里自带的那个发请求的玩意儿老是出问题,不稳定,用起来也别扭。
开始折腾
我就寻思着得找个靠谱点的家伙来干这活。问问组里的老哥,他们推荐说可以用 Apache 的 HttpClient,说这玩意儿稳定,用的人多。行,那就试试。
第一步自然是去找这个 `*` 包。那时候不像现在用 Maven 或 Gradle 那么方便,好多老项目还是手动管理依赖。我记得是去 Apache 官网下的,找好一会儿才找到对应的版本。下回来一个压缩包,里面除 `*`,好像还有几个别的相关的 JAR,比如 `*`、`*` 什么的,说是依赖,得一块儿用。
拿到 JAR 包后,我就把它一股脑儿复制到项目的 `WEB-INF/lib` 目录下(是个 Web 项目)。然后在开发工具(好像是 Eclipse?)里,把这几个 JAR 添加到项目的构建路径(Build Path)里去。这样代码里才能认得 HttpClient 相关的类。
动手写代码
接下来就是写代码。一开始就是想先试试最简单的 GET 请求,看看能不能通。
我照着网上找的例子,大概是这么写的:
- 先弄一个 HttpClient 对象出来,好像是 `HttpClient client = new HttpClient();` 这样。
- 然后创建一个请求方法,比如 GET 请求,就用 `GetMethod method = new GetMethod("目标接口的地址");`。
- 接着就是执行这个方法,`*(method);` 这句代码一跑,请求就发出去。
- 得处理返回结果。我记得当时是通过 `*();` 直接拿到返回的字符串。打印出来看看,通,能拿到数据!心里踏实一半。
后来又试 POST 请求。稍微麻烦点,要用 `PostMethod`,然后还得给它塞参数,用 `*("参数名", "参数值");` 这样一个个加进去。试下,也跑通。
遇到些坑
看着挺顺利,但实际用起来还是踩几个坑。
第一个是中文乱码。 调一个返回 JSON 数据的接口,里面有中文,结果拿回来的字符串里中文全是问号或者奇奇怪怪的符号。搞半天,发现是编码问题。不能直接用 `getResponseBodyAsString()`,得先用 `*()` 拿到输入流,然后用 `InputStreamReader` 指定正确的编码(比如 UTF-8)去读这个流,再转成字符串,这才解决乱码问题。真是折腾。
第二个是连接释放。 一开始没注意,请求跑完就完事。后来发现跑一段时间后,程序会卡住或者报连接超时的错误。查资料才知道,每次请求完,底层的连接资源需要手动释放,不然就会一直占着,用完也不还回去,连接池满就没法新建连接。关键一步 是要在 `finally` 块里调用 `*();`。加上这个之后,问题就解决。
第三个是超时设置。 有时候调用的外部接口响应比较慢,默认的超时时间可能不够,导致请求失败。后来学会在创建 HttpClient 实例的时候,给它设置连接超时和读取超时的时间,这样能让程序更有耐心一点,不容易因为网络波动或者对方接口慢就直接挂掉。
搞定
就这样,加依赖、写代码、踩坑、填坑,反反复复弄几天,总算是把用 `*` 发请求这块给摸熟。后面项目里所有需要对外发 HTTP 请求的地方,都统一换成这套东西,确实比之前那个稳定多。
虽然现在 Java 自己也内置新的 HttpClient (Java 11 开始),而且像 OkHttp、Retrofit 这些库也很好用,但在当时那个环境下,Apache 的 HttpClient 确实帮大忙。算是一段挺实在的实践经历,把这些基础的东西搞明白,后面再用其他类似的工具,上手也快很多。