Java解析http协议字符串

HTTP协议简介

HTTP(Hypertext Transfer Protocol)是一种用于传输超文本的应用层协议。它是现代互联网的基础之一,用于在客户端和服务器之间传输数据。在本文中,我们将探讨如何使用Java解析HTTP协议字符串,并将其封装成一个HttpRequest类的过程。

HTTP协议是一种无状态的、请求-响应式的协议,基于文本的,客户端通过发送请求到服务器来获取资源,服务器通过发送响应来回应请求。HTTP请求通常包含请求行、请求头和请求体,而HTTP响应包含响应行、响应头和响应体。

解析HTTP请求的过程

首先,我们需要将接收到的HTTP协议字符串分解为请求行、请求头和请求体等部分。接下来,我们将逐步解析这些部分并提取出有用的信息。

解析请求行

请求行包含了HTTP方法、请求的URL和协议版本。我们可以通过找到第一个换行符来划分请求行,并然后再通过空格来划分方法、URL和协议版本。

ini 复制代码
import java.util.HashMap;
import java.util.Map;

public class HttpStringParsingDemo {
    public static void main(String[] args) {
        // 带路径参数和查询字符串参数的HTTP请求字符串
        String httpRequestString = "GET /api/user/1/blogs?page=1&size=10 HTTP/1.1\r\n" +
                "Host: www.juejin.cn\r\n" +
                "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)\r\n" +
                "Accept: text/html,application/xhtml+xml\r\n\r\n";

        // 将请求字符串分割成行
        String[] requestLines = httpRequestString.split("\r?\n");

        // 将第一行(请求行)再次分割成各部分
        String[] requestLineParts = requestLines[0].split(" ");
        String method = requestLineParts[0];
        String fullUrl = requestLineParts[1];
        String protocolVersion = requestLineParts[2];

        // 解析URL,提取路径和查询字符串
        String[] urlParts = fullUrl.split("\?");
        String path = urlParts[0];
        String queryString = urlParts.length > 1 ? urlParts[1] : "";

        // 提取路径参数
        Map<String, String> pathParams = new HashMap<>();
        String[] pathSegments = path.split("/");
        if (pathSegments.length > 3) {  // Assuming at least 3 segments (/api/user/{user_id}/blogs)
            pathParams.put("user_id", pathSegments[3]);
        }

        // 提取查询字符串参数
        Map<String, String> queryParams = new HashMap<>();
        String[] querySegments = queryString.split("&");
        for (String querySegment : querySegments) {
            String[] keyValue = querySegment.split("=");
            if (keyValue.length == 2) {
                queryParams.put(keyValue[0], keyValue[1]);
            }
        }

        // 打印提取的信息
        System.out.println("HTTP方法: " + method);
        System.out.println("路径: " + path);
        System.out.println("路径参数: " + pathParams);
        System.out.println("查询字符串: " + queryParams);
        System.out.println("协议版本: " + protocolVersion);
    }
}


>>> out
HTTP方法: GET
路径: /api/user/1/blogs
路径参数: {user_id=1}
查询字符串: {size=10, page=1}
协议版本: HTTP/1.1

我这里的路径参数 user_id 是硬写上去的,web框架处理路径参数一般通过正则来匹配,例如java的一些注解 @PathVariable("user_id") Integer user_id 提取出来

解析请求头:

请求头包含了多个键值对,每个键值对表示一个请求头字段和对应的值。我们可以循环遍历请求行之后的每一行,通过找到冒号来划分字段名和字段值。

ini 复制代码
import java.util.HashMap;
import java.util.Map;

public class HttpHeaderParsingDemo {
    public static void main(String[] args) {
        // 带请求头的HTTP请求字符串
        String httpRequestString = "GET /headers HTTP/1.1\r\n" +
                "Host: www.juejin.cn\r\n" +
                "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)\r\n" +
                "Accept: text/html,application/xhtml+xml\r\n\r\n";

        // 将请求字符串分割成行
        String[] requestLines = httpRequestString.split("\r?\n");

        // 解析请求头字段
        Map<String, String> headers = new HashMap<>();
        for (int i = 1; i < requestLines.length; i++) {
            String[] headerParts = requestLines[i].split(": ");
            if (headerParts.length == 2) {
                String headerName = headerParts[0];
                String headerValue = headerParts[1];
                headers.put(headerName, headerValue);
            }
        }

        // 打印提取的请求头信息
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
    }
}


>>> out
Accept: text/html,application/xhtml+xml
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
Host: www.juejin.cn

请求头信息也是通过 HashMap 来存储

解析请求体:

如果是POST请求等包含请求体的请求,我们可以从请求体部分提取出数据。这部分通常需要根据请求头中的Content-Length来确定请求体的长度,然后读取相应长度的数据。

swift 复制代码
import com.alibaba.fastjson.JSON;
import java.util.Map;
import java.util.HashMap;

public class HttpReqBodyDemo {
    public static void main(String[] args) {
        // 带JSON请求体的HTTP POST请求字符串
        String httpRequestString = "POST /user/login HTTP/1.1\r\n" +
                "Host: www.juejin.cn\r\n" +
                "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)\r\n" +
                "Content-Length: 22\r\n" +
                "Content-Type: application/json\r\n\r\n" +
                "{"username":"xiao","password":"123"}";

        // 将请求字符串分割成行
        String[] requestLines = httpRequestString.split("\r?\n");

        // 解析请求头字段
        // 这里可以参考之前示例中的方法解析请求头

        // 解析请求体
        String requestBody = "";
        if (headers.containsKey("Content-Length")) {
            int contentLength = Integer.parseInt(headers.get("Content-Length"));
            requestBody = requestLines[requestLines.length - 1];
        }

        // 解析JSON数据并封装成Map
        Map<String,String> map = (Map<String, String>) JSON.parse(requestBody);

        // 打印封装的Map数据
        for (Map.Entry<String, String> entry : jsonMap.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
    }
}

当然要根据不同的Content-Type分别处理,这里就简单处理个Json数据,毕竟也比较常用。

封装成HttpRequest类

现在我们已经成功地从HTTP协议字符串中解析出了请求行、请求头和请求体等信息。接下来,我们可以将这些信息封装成一个HttpRequest类,以便更方便地使用和处理。

typescript 复制代码
import com.alibaba.fastjson.JSON;
import java.util.Map;

public class HttpRequest {
    private String method;
    private String url;
    private String protocolVersion;
    private Map<String, String> headers;
    private Map<String, String> queryParameters;
    private Map<String, String> requestBody;

    public HttpRequest(String method, String url, String protocolVersion,
                        Map<String, String> headers, Map<String, String> queryParameters,
                        Map<String, String> requestBody) {
        this.method = method;
        this.url = url;
        this.protocolVersion = protocolVersion;
        this.headers = headers;
        this.queryParameters = queryParameters;
        this.requestBody = requestBody;
    }

    public String getMethod() {
        return method;
    }

    public String getUrl() {
        return url;
    }

    public String getProtocolVersion() {
        return protocolVersion;
    }

    public Map<String, String> getHeaders() {
        return headers;
    }

    public Map<String, String> getQueryParameters() {
        return queryParameters;
    }

    public Map<String, String> getRequestBody() {
        return requestBody;
    }
}
ini 复制代码
import com.alibaba.fastjson.JSON;
import java.util.Map;

public class HttpRequestParsingDemo {
    public static void main(String[] args) {
        // HTTP请求字符串
        String httpRequestString = "POST /submit?test=xiao&code=hui HTTP/1.1\r\n" +
                "Host: www.juejin.cn\r\n" +
                "User-Agent: Mozilla/5.0\r\n" +
                "Content-Length: 27\r\n" +
                "Content-Type: application/json\r\n" +
                "\r\n" +
                "{"username":"xiao","age":20}";

        // 将请求字符串分割成行
        String[] requestLines = httpRequestString.split("\r?\n");

        // 解析请求行
        String[] requestLineParts = requestLines[0].split(" ");
        String method = requestLineParts[0];
        String url = requestLineParts[1];
        String protocolVersion = requestLineParts[2];

        // 解析请求头部分
        Map<String, String> headers = new HashMap<>();
        for (int i = 1; i < requestLines.length; i++) {
            String[] headerParts = requestLines[i].split(": ");
            if (headerParts.length == 2) {
                String headerName = headerParts[0];
                String headerValue = headerParts[1];
                headers.put(headerName, headerValue);
            }
        }
        
        // 解析查询字符串参数
        Map<String, String> queryParams = new HashMap<>();
        String[] querySegments = queryString.split("&");
        for (String querySegment : querySegments) {
            String[] keyValue = querySegment.split("=");
            if (keyValue.length == 2) {
                queryParams.put(keyValue[0], keyValue[1]);
            }
        }

        // 解析JSON请求体
        String requestBody = "";
        if (headers.containsKey("Content-Length")) {
            int contentLength = Integer.parseInt(headers.get("Content-Length"));
            requestBody = requestLines[requestLines.length - 1];
        }

        // 解析JSON数据并封装成Map
        Map<String,String> requestBody = (Map<String, String>) JSON.parse(requestBody);

        // 创建HttpRequest对象
        HttpRequest httpRequest = new HttpRequest(
                method,
                url,
                protocolVersion,
                headers,
                queryParams,
                requestBody)
        );

        // 打印HttpRequest对象中的信息
        System.out.println("HTTP方法: " + httpRequest.getMethod());
        System.out.println("URL: " + httpRequest.getUrl());
        System.out.println("协议版本: " + httpRequest.getProtocolVersion());
        System.out.println("请求头部分: " + httpRequest.getHeaders());
        System.out.println("查询字符串参数: " + httpRequest.getQueryParameters());
        System.out.println("JSON请求体: " + httpRequest.getRequestBody());
    }
}

总结

在本文中,我们探讨了如何使用Java解析HTTP协议字符串,并将其封装成了一个HttpRequest类。通过逐步解析请求行、请求头和请求体,我们能够从协议字符串中提取出有用的信息,并将其封装成一个类对象,以便更方便地使用和处理。这种方法可以帮助开发人员在处理HTTP请求时更加灵活和高效,为构建Web应用程序和服务器端处理提供了基础。虽然是一个简单的字符串解析封装,但通过深入理解HTTP协议的解析过程,我们能够更好地理解互联网信息交互原理。

相关推荐
程序员-珍10 分钟前
使用openapi生成前端请求文件报错 ‘Token “Integer“ does not exist.‘
java·前端·spring boot·后端·restful·个人开发
2401_8572979137 分钟前
招联金融2025校招内推
java·前端·算法·金融·求职招聘
福大大架构师每日一题1 小时前
23.1 k8s监控中标签relabel的应用和原理
java·容器·kubernetes
金灰1 小时前
HTML5--裸体回顾
java·开发语言·前端·javascript·html·html5
菜鸟一皓1 小时前
IDEA的lombok插件不生效了?!!
java·ide·intellij-idea
爱上语文1 小时前
Java LeetCode每日一题
java·开发语言·leetcode
bug菌1 小时前
Java GUI编程进阶:多线程与并发处理的实战指南
java·后端·java ee
程序猿小D2 小时前
第二百六十九节 JPA教程 - JPA查询OrderBy两个属性示例
java·开发语言·数据库·windows·jpa
极客先躯2 小时前
高级java每日一道面试题-2024年10月3日-分布式篇-分布式系统中的容错策略都有哪些?
java·分布式·版本控制·共识算法·超时重试·心跳检测·容错策略
夜月行者3 小时前
如何使用ssm实现基于SSM的宠物服务平台的设计与实现+vue
java·后端·ssm