如何优雅的自己包装一个Http工具类

1、Http请求概述

HTTP 请求是用来与服务器进行交互的,在Web开发中占有核心地位。常见的HTTP请求方法有多种,每种方法都有其特定的用途。以下是主要的HTTP请求方法及其作用:

1.1、GET

1.用途:请求从服务器获取数据。
2.使用场景:当浏览器向服务器请求一个网页时,通常使用GET请求。GET请求也经常用于获取资源,如图片、数据列表等。
3.特点:数据通常会附加在URL中(即请求参数)。GET请求一般是“幂等”的(同样的请求可以重复多次而不会产生副作用)。不建议用于传递敏感数据(比如密码),因为数据在URL中是可见的。

1.2、POST

1.用途:向服务器提交数据以创建资源。
2.使用场景:当需要提交表单数据、上传文件,或者发送复杂的数据给服务器时使用。
3.特点:数据在请求体中发送,不会出现在URL中。POST请求是“非幂等”的(同样的请求多次执行可能会导致不同的结果,比如多次提交会创建多个相同的资源)。支持更大的数据量。

1.3、 PUT

1.用途:向服务器发送数据以更新资源,如果资源不存在,则可以选择创建新资源。
2.使用场景:用来更新已有记录的场景,如修改用户资料信息。
3.特点:请求是“幂等”的(同样的请求多次执行会得到相同的结果,不会重复增加资源)。通常将数据发送到特定的URL路径。

1.4、DELETE

1.用途:删除指定的资源。
2.使用场景:用来删除记录或文件等资源,比如删除用户或文章。
3.特点:请求是“幂等”的,重复发送删除请求通常不会造成额外的影响(前提是资源不存在时返回404等状态码)。

1.5、HEAD

1.用途:与GET请求类似,但只返回头部信息,不返回具体内容。
2.使用场景:用于检查资源的元数据,比如是否存在、是否被修改等,而不获取实际数据。
3.特点:常用于性能优化和资源检查,如在判断内容是否需要更新时使用。

2、典型使用示例

1、GET 请求用户信息:GET /users/123
2、POST 提交表单数据:POST /form
3、PUT 更新文章内容:PUT /posts/456
4、DELETE 删除记录:DELETE /records/789

不同的HTTP请求方法针对不同场景设计,规范了客户端与服务器之间如何交互并保持数据一致性。

3、HTTP&HTTPS

1、HTTP(HyperText Transfer Protocol):是一种应用层协议,主要用于在客户端和服务器之间传输网页数据,如HTML文档、图像、视频等。HTTP是一种明文传输协议,意味着数据在传输时没有经过加密。
2、HTTPS(HyperText Transfer Protocol Secure):是在HTTP的基础上增加了安全层,通过使用SSL(Secure Sockets Layer)或TLS(Transport Layer Security)对数据进行加密和身份验证。它可以确保通信的机密性、完整性和真实性。

3.1、HTTP 和 HTTPS 的主要区别

3.1.1、安全性

1、HTTP 是明文传输,数据在客户端与服务器之间传输时容易被第三方截获和窃听。这对敏感信息如密码、信用卡号等存在很大风险。
2、HTTPS 通过加密机制提供了更高的安全性。传输数据经过加密,确保通信内容不被窃取、篡改和伪造。

3.1.2、端口号

1、HTTP 使用的默认端口号是 80。
2、HTTPS 使用的默认端口号是 443。

3.1.3、数据传输方式

1、HTTP 直接通过TCP进行传输。
2、HTTPS 通过SSL/TLS协议进行加密,然后再通过TCP进行传输。也就是说,HTTPS是HTTP和SSL/TLS的结合。

3.1.4、证书验证

1、HTTP 不需要证书即可工作。
2、HTTPS 需要服务器端配置SSL/TLS证书,通过证书来验证服务器的身份并加密数据。

3.2、HTTP 和 HTTPS 的工作原理

3.2.1、HTTP 的工作原理

1、建立连接:客户端与服务器之间通过TCP/IP建立连接。
2、发送请求:客户端向服务器发送HTTP请求,包括请求方法、URL、头部信息等。
3、服务器处理请求并返回响应:服务器处理请求后返回响应,包括状态码、头部和数据内容等。
4、关闭连接(HTTP/1.0)或保持连接(HTTP/1.1/2/3):连接关闭或保持,以便后续请求使用。

HTTP 是一种无状态的明文协议,数据在传输时没有加密,所以通信的隐私性和安全性无法保证。

3.2.2、HTTPS 的工作原理

1、HTTPS 工作原理相对复杂,因为它涉及加密和身份验证过程。以下是 HTTPS 的大致流程:
2、建立连接和握手:客户端与服务器建立连接并发起 SSL/TLS 握手过程。这个过程涉及:
3、客户端发送Hello消息:客户端向服务器发送请求,说明它支持的加密算法和TLS版本。
4、服务器发送证书和响应:服务器返回一个数字证书,其中包含其公钥和其他信息,供客户端验证。
5、客户端验证证书:客户端验证服务器的证书,确保其合法性和真实性。如果证书有效,客户端生成一个“会话密钥”,并用服务器的公钥加密后发送给服务器。
6、建立加密通信通道:服务器使用其私钥解密会话密钥,双方使用该会话密钥来对接下来的通信进行对称加密。这意味着后续传输的数据都是加密的,第三方无法轻易解读。
7、发送请求和响应:在加密通道上,客户端发送HTTP请求,服务器处理并返回响应,整个通信过程都被加密。
8、关闭连接:通信完成后,连接可能被关闭(如果使用短连接)。

4、封装的工具类代码

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.util.Map;

@Slf4j
public class HttpUtil {

    private static final int MAX_RETRIES = 5;
    private static final int TIMEOUT = 5000;

    public static <T> T sendGet(String url, Class<T> clazz) throws Exception {
        return sendHttpRequest("GET", url, null, null, clazz);
    }

    public static <T> T sendPost(String url, String postData, Map<String, String> headers, Class<T> clazz) throws Exception {
        return sendHttpRequest("POST", url, postData, headers, clazz);
    }

    private static <T> T sendHttpRequest(String method, String url, String postData, Map<String, String> headers, Class<T> clazz) throws Exception {
        int retries = 0;

        while (retries < MAX_RETRIES) {
            HttpURLConnection connection = null;

            try {
                URL requestUrl = new URL(url);
                connection = (HttpURLConnection) requestUrl.openConnection();
                connection.setRequestMethod(method);
                connection.setConnectTimeout(TIMEOUT);
                connection.setReadTimeout(TIMEOUT);

                if ("POST".equalsIgnoreCase(method)) {
                    connection.setDoOutput(true);
                    connection.setRequestProperty("Content-Type", "application/json");
                    if (headers != null) {
                        for (Map.Entry<String, String> entry : headers.entrySet()) {
                            connection.setRequestProperty(entry.getKey(), entry.getValue());
                        }
                    }
                    try (OutputStream outputStream = connection.getOutputStream()) {
                        outputStream.write(postData.getBytes());
                        outputStream.flush();
                    }
                }

                int responseCode = connection.getResponseCode();
                if (responseCode == HttpURLConnection.HTTP_OK) {
                    return handleResponse(connection, clazz);
                } else if (responseCode == HttpURLConnection.HTTP_FORBIDDEN) {
                    retries++;
                    log.warn("{} request failed with 403, retrying {}/{} in {} ms...", method, retries, MAX_RETRIES, 10000 * retries);
                    if (retries == MAX_RETRIES) {
                        throw new RuntimeException("Max retries reached for " + method + " request. Please try again later.");
                    }
                    Thread.sleep(10000L * retries);
                } else {
                    throw new RuntimeException("HTTP " + method + " Request Failed with Error code : " + responseCode);
                }
            } catch (SocketTimeoutException e) {
                retries++;
                log.warn("{} request timed out, retrying {}/{} in {} ms...", method, retries, MAX_RETRIES, 10000 * retries);
                if (retries == MAX_RETRIES) {
                    throw new RuntimeException("Max retries reached for " + method + " request.", e);
                }
                Thread.sleep(10000L * retries);
            } finally {
                if (connection != null) {
                    connection.disconnect();
                }
            }
        }
        return null;
    }

    private static <T> T handleResponse(HttpURLConnection connection, Class<T> clazz) {
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
            StringBuilder response = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
            String responseBody = response.toString();

            if (clazz == String.class) {
                return clazz.cast(responseBody);
            } else if (clazz == JSONObject.class) {
                return clazz.cast(JSON.parseObject(responseBody));
            } else if (clazz == JSONArray.class) {
                return clazz.cast(JSON.parseArray(responseBody));
            } else {
                return JSON.parseObject(responseBody, clazz);
            }
        } catch (Exception e) {
            throw new RuntimeException("Error parsing response", e);
        }
    }
}

此工具类,可以代码重试,可以根据你想要返回的类型,自定义一个返回类,比较方便快捷。

end
  • 作者:lishe (联系作者)
  • 发表时间:2024-11-18 10:17
  • 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)
  • 转载声明:如果是转载博主转载的文章,请附上原文链接
  • 公众号转载:请在文末添加作者公众号二维码(公众号二维码见右边,欢迎关注)
  • 评论