HttpClient调用外部接口业务别忘了超时配置!公司工具类打包好啦

前言

微信图片_20240109170459.png

        在工作中,往往会遇到需要对接外部接口的业务需求,根据接口文档确定请求IP以及相关的参数数据需求后,通过HttpClient进行第三方外部接口的调用。在这种业务中,也要考虑好请求超时导致的接口报错的处理。为什么呢?就我公司业务而言,我们这边的视频或者说融合通讯,因为厂商多,设备型号杂,经常都有调用不通的情况。今天正常的视频可能明天就不行了,如果后端这里不处理超时,前端如果无法拿到设备信息或者设备ID,页面的报错信息可能反应的就是接口报错了。这显然是不合情理的,为此,我们可以考虑加一个请求超时的参数(在配置文件中读取自定义参数) ,控制一下。本文就HttpClient做一个简单的快速入门,并搭配好我编写的一个完整工具类,希望可以帮助大家在第三方接口调用业务中有所帮助。

实现思路步骤

  1. 创建 HttpClient 对象,可以使用 HttpClients.createDefault() 方法。

  2. 确定请求方法类型

    • 如果是无参数的 GET 请求,则直接使用构造方法 HttpGet(String url) 创建 HttpGet 对象即可;如果是带参数的 GET 请求,则可以先使用 URIBuilder(String url) 创建对象,再调用 addParameter(String param, String value) 或者 setParameter(String param, String value) 方法来设置请求参数,并调用 build() 方法构建一个 URI 对象。只有构造方法 HttpGet(URI uri) 可以创建 HttpGet 对象。
    • 如果是无参数的GET请求,则直接使用构造方法HttpPost(String url)创建HttpPost对象即可; 如果是带参数POST请求,先构建**HttpEntity对象并设置请求参数,然后调用setEntity(HttpEntity entity)** 创建HttpPost对象。
  3. 加载配置类中的超时配置数据,配置在 RequestConfig 对象中,将该对象配置到具体的HttpPost / HttpGet 对象里,设置好超时规则

  4. 创建 HttpResponse,调用 HttpClient 对象的 execute(HttpUriRequest request) 方法发送请求,该方法返回一个 HttpResponse。调用 HttpResponse 的 getAllHeaders() 、getHeaders(String name) 等方法可以获取服务器的响应头;调用 HttpResponse 的 getEntity() 方法可以获取 HttpEntity 对象,该对象包装了服务器的响应内容。程序可以通过该对象获取服务器的响应内容。通过调用 getStatusLine().getStatusCode() 可以获取响应状态码。

  5. 通过 e instanceof SocketTimeoutException 和 e instanceof ConnectTimeoutException 来抛出请求失败的具体异常,在调用方通过**catch (SocketTimeoutException e)** 和** catch (SocketTimeoutException e)** 来进行捕获,并响应自定义的异常消息

工具类

        本工具类主要涉及了发送GET请求和POST请求的情况,搭配了超时处理机制,同时针对请求参数和请求头参数的配置进行动态配置,满足无参和有参的请求需求。

 

java

复制代码

/** * Http请求工具类 * @author 吴志鑫 */ public class HttpUtil { ​    /** * 读取配置文件中自定义的超时参数 */    @Resource    Propertise propertise; ​    private static HttpUtil httpUtil; ​    @PostConstruct    public void init(){        httpUtil = this;        httpUtil.propertise = propertise;   } ​    /**     * 发送Post请求(带请求头数据)     * @param url 请求url     * @param params 请求参数map集合     * @param headers 请求头参数map集合     * @return 响应对象     * @param <T> 请求参数值类型     */    public static <T> HttpResponse sendPost(String url, Map<String, T> params, Map<String, String> headers) throws ConnectTimeoutException, SocketTimeoutException {                // 创建Httpclient对象        HttpClient httpClient = HttpClients.createDefault(); ​        // 配置相关超时参数        RequestConfig requestConfig = RequestConfig.custom()               .setConnectTimeout(httpUtil.propertise.getConnectionTimeOut())               .setSocketTimeout(httpUtil.propertise.getSocketTimeOut()).build(); ​        // 创建 HttpPost 请求对象,如果是Get请求就用HttpGet        HttpPost httpPost = new HttpPost(url); ​        // 设置超时参数        httpPost.setConfig(requestConfig); ​        if (params != null){            // 将 params 转换为 JSON 格式的字符串            String json = new Gson().toJson(params); ​            StringEntity requestEntity = new StringEntity(json, ContentType.APPLICATION_JSON);            httpPost.setEntity(requestEntity);       } ​        if (headers != null && !headers.isEmpty()){            // 设置请求头            headers.forEach(httpPost::setHeader);       } ​        // 发送请求并获取响应        try {            return httpClient.execute(httpPost);       } catch (IOException e) { ​            // 因为超时导致的抛出超时异常            if (e instanceof ConnectTimeoutException) {                throw (ConnectTimeoutException) e;           } ​            // 因为套接字超时时间导致的抛出套接字超时异常            if (e instanceof SocketTimeoutException) {                throw (SocketTimeoutException) e;           }            throw new RuntimeException(e);       }   } ​    /**     * 发送GET请求     * @param url 请求路径     * @param params 请求参数的map集合     * @return 响应对象     */    public static HttpResponse sendGet(String url, Map<String, String> params, Map<String, String> headers) throws ConnectTimeoutException, SocketTimeoutException { ​        // 创建Httpclient对象        HttpClient httpClient = HttpClients.createDefault(); ​        String finalUrl = url;        if(params != null){            try {                // 构建带有参数的 URI                URIBuilder builder = new URIBuilder(url);                params.forEach(builder::addParameter);                finalUrl = builder.build().toString();           } catch (URISyntaxException e) {                throw new RuntimeException(e);           }       } ​        // 创建 HttpPost 请求对象,如果是Get请求就用HttpGet        HttpGet httpGet = new HttpGet(finalUrl); ​        // 配置相关超时参数        RequestConfig requestConfig = RequestConfig.custom()               .setConnectTimeout(httpUtil.propertise.getConnectionTimeOut())               .setSocketTimeout(httpUtil.propertise.getSocketTimeOut()).build(); ​        // 设置超时参数        httpGet.setConfig(requestConfig); ​        if (headers != null && !headers.isEmpty()){            // 设置请求头            headers.forEach(httpGet::setHeader);       } ​        // 发送请求并获取响应        try {            // 发送请求并获取响应            return httpClient.execute(httpGet);       } catch (IOException e) { ​            // 因为超时导致的抛出超时异常            if (e instanceof ConnectTimeoutException) {                throw (ConnectTimeoutException) e;           } ​            // 因为套接字超时时间导致的抛出套接字超时异常            if (e instanceof SocketTimeoutException) {                throw (SocketTimeoutException) e;           }            throw new RuntimeException(e);       }   } }

超时参数配置类

        一般这种关键参数都是自定义进行调控,所以我们需要将其暴露到配置文件中,这样子才能减少关键配置的耦合性

 

kotlin

复制代码

/** * 请求超时数据配置类 * @author 吴志鑫 */ @Component public class Propertise { ​    /**     * 建立连接的最大等待时间     */    private Integer connectionTimeOut; ​    /**     * 从服务器读取数据的最大等待时间     */    private Integer socketTimeOut; ​    @Autowired    public Propertise(@Value("${http-request-connection-timeout}") Integer connectionTimeOut                   , @Value("${http-request-socket-timeout}") Integer socketTimeOut) {        if (connectionTimeOut == null) {            throw new IllegalArgumentException("http-request-connection-timeout cannot be null");       }        if (socketTimeOut == null) {            throw new IllegalArgumentException("http-request-socket-timeout cannot be null");       }        this.connectionTimeOut = connectionTimeOut;        this.socketTimeOut = socketTimeOut;   } ​    public Integer getConnectionTimeOut() {        return connectionTimeOut;   } ​    public Integer getSocketTimeOut() {        return socketTimeOut;   } }

调用例子

 

typescript

复制代码

public static void main(String[] args) { ​        // 请求的 URL        String url = "https://httpbin.org/post"; ​        // 请求参数        Map<String, String> formparams = new HashMap<>(2);        formparams.put("clientId", "953251617");        formparams.put("clientSecret", "Cmcc#8888"); ​        HttpResponse httpResponse = null;        try {            httpResponse = HttpUtil.sendPost(url, formparams, null);       } catch (ConnectTimeoutException e) { ​            // 自定义返回连接超时的错误消息            String errorMessage = "连接超时,请重试或联系管理员"; ​            // 返回错误消息给调用者.......... ​            throw new RuntimeException(e);       } catch (SocketTimeoutException e) {            // 自定义返回套接字超时的错误消息            String errorMessage = "套接字超时,请重试或联系管理员"; ​            // 返回错误消息给调用者.......... ​            throw new RuntimeException(e);       } ​        HttpEntity responseEntity = httpResponse.getEntity();        String responseString = null;        try {            responseString = EntityUtils.toString(responseEntity,"UTF-8");       } catch (IOException e) {            throw new RuntimeException(e);       } ​        // 处理响应结果        System.out.println(responseString); ​   }

总结

        本文主要讲解了 HttpGet 请求响应的一般步骤。在使用 HttpClient 进行 HttpGet 请求时,我们需要先创建 HttpClient 对象,然后根据请求是否带参数选择不同的方式创建 HttpGet 对象。接着,通过执行 execute(HttpUriRequest request) 方法发送请求,获取 HttpResponse 对象,并通过该对象获取服务器的响应头和响应内容。最后需要释放连接。通过本文的介绍,读者可以了解到 HttpGet 请求的基本操作流程,对于使用 HttpClient 进行 HttpGet 请求的开发工作会有更深入的理解。

  • 21
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值