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

相关推荐
异常君6 分钟前
深入 JVM:线程池源码剖析与性能调优全攻略
java·jvm·后端
Light___mmm7 分钟前
注入Java Bean的方式
java
xcLeigh15 分钟前
HTML5好看的水果蔬菜在线商城网站源码系列模板4
java·前端·源码·html5
烟沙九洲39 分钟前
算法的时间复杂度
java·算法
写bug写bug1 小时前
小小 Stream,一篇文章拿捏它
java·后端
写bug写bug1 小时前
好用的Lombok注解
java·后端
码熔burning1 小时前
【NIO番外篇】之组件 Selector
java·io·nio·selector
triticale1 小时前
【数论】线性筛质数
java·算法
百锦再2 小时前
Android ImageView 使用详解
android·java·app·手机·安卓·studio
续亮~2 小时前
提示词 (Prompt)
java·人工智能·prompt·ai编程·springai