Java解析http協(xié)議字符串的方法實(shí)現(xiàn)
HTTP協(xié)議簡(jiǎn)介
HTTP(Hypertext Transfer Protocol)是一種用于傳輸超文本的應(yīng)用層協(xié)議。它是現(xiàn)代互聯(lián)網(wǎng)的基礎(chǔ)之一,用于在客戶端和服務(wù)器之間傳輸數(shù)據(jù)。在本文中,我們將探討如何使用Java解析HTTP協(xié)議字符串,并將其封裝成一個(gè)HttpRequest類(lèi)的過(guò)程。
HTTP協(xié)議是一種無(wú)狀態(tài)的、請(qǐng)求-響應(yīng)式的協(xié)議,基于文本的,客戶端通過(guò)發(fā)送請(qǐng)求到服務(wù)器來(lái)獲取資源,服務(wù)器通過(guò)發(fā)送響應(yīng)來(lái)回應(yīng)請(qǐng)求。HTTP請(qǐng)求通常包含請(qǐng)求行、請(qǐng)求頭和請(qǐng)求體,而HTTP響應(yīng)包含響應(yīng)行、響應(yīng)頭和響應(yīng)體。

解析HTTP請(qǐng)求的過(guò)程
首先,我們需要將接收到的HTTP協(xié)議字符串分解為請(qǐng)求行、請(qǐng)求頭和請(qǐng)求體等部分。接下來(lái),我們將逐步解析這些部分并提取出有用的信息。
解析請(qǐng)求行
請(qǐng)求行包含了HTTP方法、請(qǐng)求的URL和協(xié)議版本。我們可以通過(guò)找到第一個(gè)換行符來(lái)劃分請(qǐng)求行,并然后再通過(guò)空格來(lái)劃分方法、URL和協(xié)議版本。
import java.util.HashMap;
import java.util.Map;
public class HttpStringParsingDemo {
? ? public static void main(String[] args) {
? ? ? ? // 帶路徑參數(shù)和查詢字符串參數(shù)的HTTP請(qǐng)求字符串
? ? ? ? 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";
? ? ? ? // 將請(qǐng)求字符串分割成行
? ? ? ? String[] requestLines = httpRequestString.split("\r?\n");
? ? ? ? // 將第一行(請(qǐng)求行)再次分割成各部分
? ? ? ? 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] : "";
? ? ? ? // 提取路徑參數(shù)
? ? ? ? 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]);
? ? ? ? }
? ? ? ? // 提取查詢字符串參數(shù)
? ? ? ? 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("路徑參數(shù): " + pathParams);
? ? ? ? System.out.println("查詢字符串: " + queryParams);
? ? ? ? System.out.println("協(xié)議版本: " + protocolVersion);
? ? }
}>>> out
HTTP方法: GET
路徑: /api/user/1/blogs
路徑參數(shù): {user_id=1}
查詢字符串: {size=10, page=1}
協(xié)議版本: HTTP/1.1
我這里的路徑參數(shù) user_id 是硬寫(xiě)上去的,web框架處理路徑參數(shù)一般通過(guò)正則來(lái)匹配,例如java的一些注解 @PathVariable("user_id") Integer user_id 提取出來(lái)
解析請(qǐng)求頭:
請(qǐng)求頭包含了多個(gè)鍵值對(duì),每個(gè)鍵值對(duì)表示一個(gè)請(qǐng)求頭字段和對(duì)應(yīng)的值。我們可以循環(huán)遍歷請(qǐng)求行之后的每一行,通過(guò)找到冒號(hào)來(lái)劃分字段名和字段值。
import java.util.HashMap;
import java.util.Map;
public class HttpHeaderParsingDemo {
? ? public static void main(String[] args) {
? ? ? ? // 帶請(qǐng)求頭的HTTP請(qǐng)求字符串
? ? ? ? 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";
? ? ? ? // 將請(qǐng)求字符串分割成行
? ? ? ? String[] requestLines = httpRequestString.split("\r?\n");
? ? ? ? // 解析請(qǐng)求頭字段
? ? ? ? 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);
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? // 打印提取的請(qǐng)求頭信息
? ? ? ? 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
請(qǐng)求頭信息也是通過(guò) HashMap 來(lái)存儲(chǔ)
解析請(qǐng)求體:
如果是POST請(qǐng)求等包含請(qǐng)求體的請(qǐng)求,我們可以從請(qǐng)求體部分提取出數(shù)據(jù)。這部分通常需要根據(jù)請(qǐng)求頭中的Content-Length來(lái)確定請(qǐng)求體的長(zhǎng)度,然后讀取相應(yīng)長(zhǎng)度的數(shù)據(jù)。
import com.alibaba.fastjson.JSON;
import java.util.Map;
import java.util.HashMap;
public class HttpReqBodyDemo {
? ? public static void main(String[] args) {
? ? ? ? // 帶JSON請(qǐng)求體的HTTP POST請(qǐng)求字符串
? ? ? ? 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"}";
? ? ? ? // 將請(qǐng)求字符串分割成行
? ? ? ? String[] requestLines = httpRequestString.split("\r?\n");
? ? ? ? // 解析請(qǐng)求頭字段
? ? ? ? // 這里可以參考之前示例中的方法解析請(qǐng)求頭
? ? ? ? // 解析請(qǐng)求體
? ? ? ? String requestBody = "";
? ? ? ? if (headers.containsKey("Content-Length")) {
? ? ? ? ? ? int contentLength = Integer.parseInt(headers.get("Content-Length"));
? ? ? ? ? ? requestBody = requestLines[requestLines.length - 1];
? ? ? ? }
? ? ? ? // 解析JSON數(shù)據(jù)并封裝成Map
? ? ? ? Map<String,String> map = (Map<String, String>) JSON.parse(requestBody);
? ? ? ? // 打印封裝的Map數(shù)據(jù)
? ? ? ? for (Map.Entry<String, String> entry : jsonMap.entrySet()) {
? ? ? ? ? ? System.out.println(entry.getKey() + ": " + entry.getValue());
? ? ? ? }
? ? }
}當(dāng)然要根據(jù)不同的Content-Type分別處理,這里就簡(jiǎn)單處理個(gè)Json數(shù)據(jù),畢竟也比較常用。
封裝成HttpRequest類(lèi)
現(xiàn)在我們已經(jīng)成功地從HTTP協(xié)議字符串中解析出了請(qǐng)求行、請(qǐng)求頭和請(qǐng)求體等信息。接下來(lái),我們可以將這些信息封裝成一個(gè)HttpRequest類(lèi),以便更方便地使用和處理。
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;
? ? }
}import com.alibaba.fastjson.JSON;
import java.util.Map;
public class HttpRequestParsingDemo {
? ? public static void main(String[] args) {
? ? ? ? // HTTP請(qǐng)求字符串
? ? ? ? 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}";
? ? ? ? // 將請(qǐng)求字符串分割成行
? ? ? ? String[] requestLines = httpRequestString.split("\r?\n");
? ? ? ? // 解析請(qǐng)求行
? ? ? ? String[] requestLineParts = requestLines[0].split(" ");
? ? ? ? String method = requestLineParts[0];
? ? ? ? String url = requestLineParts[1];
? ? ? ? String protocolVersion = requestLineParts[2];
? ? ? ? // 解析請(qǐng)求頭部分
? ? ? ? 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);
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? // 解析查詢字符串參數(shù)
? ? ? ? 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請(qǐng)求體
? ? ? ? String requestBody = "";
? ? ? ? if (headers.containsKey("Content-Length")) {
? ? ? ? ? ? int contentLength = Integer.parseInt(headers.get("Content-Length"));
? ? ? ? ? ? requestBody = requestLines[requestLines.length - 1];
? ? ? ? }
? ? ? ? // 解析JSON數(shù)據(jù)并封裝成Map
? ? ? ? Map<String,String> requestBody = (Map<String, String>) JSON.parse(requestBody);
? ? ? ? // 創(chuàng)建HttpRequest對(duì)象
? ? ? ? HttpRequest httpRequest = new HttpRequest(
? ? ? ? ? ? ? ? method,
? ? ? ? ? ? ? ? url,
? ? ? ? ? ? ? ? protocolVersion,
? ? ? ? ? ? ? ? headers,
? ? ? ? ? ? ? ? queryParams,
? ? ? ? ? ? ? ? requestBody)
? ? ? ? );
? ? ? ? // 打印HttpRequest對(duì)象中的信息
? ? ? ? System.out.println("HTTP方法: " + httpRequest.getMethod());
? ? ? ? System.out.println("URL: " + httpRequest.getUrl());
? ? ? ? System.out.println("協(xié)議版本: " + httpRequest.getProtocolVersion());
? ? ? ? System.out.println("請(qǐng)求頭部分: " + httpRequest.getHeaders());
? ? ? ? System.out.println("查詢字符串參數(shù): " + httpRequest.getQueryParameters());
? ? ? ? System.out.println("JSON請(qǐng)求體: " + httpRequest.getRequestBody());
? ? }
}總結(jié)
在本文中,我們探討了如何使用Java解析HTTP協(xié)議字符串,并將其封裝成了一個(gè)HttpRequest類(lèi)。通過(guò)逐步解析請(qǐng)求行、請(qǐng)求頭和請(qǐng)求體,我們能夠從協(xié)議字符串中提取出有用的信息,并將其封裝成一個(gè)類(lèi)對(duì)象,以便更方便地使用和處理。這種方法可以幫助開(kāi)發(fā)人員在處理HTTP請(qǐng)求時(shí)更加靈活和高效,為構(gòu)建Web應(yīng)用程序和服務(wù)器端處理提供了基礎(chǔ)。雖然是一個(gè)簡(jiǎn)單的字符串解析封裝,但通過(guò)深入理解HTTP協(xié)議的解析過(guò)程,我們能夠更好地理解互聯(lián)網(wǎng)信息交互原理。
到此這篇關(guān)于Java解析http協(xié)議字符串的方法實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Java解析http協(xié)議字符串內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring?Boot的優(yōu)點(diǎn)及項(xiàng)目創(chuàng)建步驟詳解
這篇文章主要介紹了Spring?Boot的優(yōu)點(diǎn)及項(xiàng)目創(chuàng)建步驟,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-09-09
IDEA使用properties配置文件進(jìn)行mysql數(shù)據(jù)庫(kù)連接的教程圖解
Properties類(lèi)是 鍵和值均為字符串的可以永久存儲(chǔ)到文件中的key-value集合。這篇文章主要介紹了IDEA使用properties配置文件進(jìn)行mysql數(shù)據(jù)路連接 ,需要的朋友可以參考下2018-10-10
使用Stargate訪問(wèn)K8ssandra的過(guò)程之Springboot整合Cassandra
這篇文章主要介紹了使用Stargate訪問(wèn)K8ssandra的過(guò)程之Springboot整合Cassandra,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-10-10
springcloud gateway如何實(shí)現(xiàn)路由和負(fù)載均衡
這篇文章主要介紹了springcloud gateway如何實(shí)現(xiàn)路由和負(fù)載均衡的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
mybatisPlus自定義批量新增的實(shí)現(xiàn)代碼
這篇文章主要介紹了mybatisPlus自定義批量新增的實(shí)現(xiàn)代碼,代碼簡(jiǎn)單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-11-11
Java Map遍歷2種實(shí)現(xiàn)方法代碼實(shí)例
這篇文章主要介紹了Java Map遍歷2種實(shí)現(xiàn)方法代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10

