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