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协议的解析过程,我们能够更好地理解互联网信息交互原理。

相关推荐
码上飞扬22 分钟前
Java大师成长计划之第22天:Spring Cloud微服务架构
java·运维·云计算
秋野酱40 分钟前
基于javaweb的SpringBoot自习室预约系统设计与实现(源码+文档+部署讲解)
java·spring boot·后端
面试官E先生1 小时前
【极兔快递Java社招】一面复盘|数据库+线程池+AQS+中间件面面俱到
java·面试
琢磨先生David1 小时前
构建优雅对象的艺术:Java 建造者模式的架构解析与工程实践
java·设计模式·建造者模式
小雅痞1 小时前
[Java][Leetcode simple]26. 删除有序数组中的重复项
java·leetcode
青云交1 小时前
Java 大视界 -- 基于 Java 的大数据分布式存储在工业互联网海量设备数据长期存储中的应用优化(248)
java·大数据·工业互联网·分布式存储·冷热数据管理·hbase 优化·kudu 应用
纸包鱼最好吃2 小时前
java基础-package关键字、MVC、import关键字
java·开发语言·mvc
唐山柳林2 小时前
城市生命线综合管控系统解决方案-守护城市生命线安全
java·安全·servlet
PgSheep2 小时前
Spring Cloud Gateway 聚合 Swagger 文档:一站式API管理解决方案
java·开发语言
蒂法就是我2 小时前
详细说说Spring的IOC机制
java·后端·spring