首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

從零構建 Java 簡易 Web 伺服器(一):Socket 與 HTTP 協議深度解析

     編輯:Java 綜合教學

從零構建 Java 簡易 Web 伺服器(一):Socket 與 HTTP 協議深度解析

本系列文章將帶領大家使用 Java 從頭編寫一個簡易的 Web 伺服器。Web 伺服器與客戶端之間的通信基於 HTTP 協議,而 HTTP 協議本質上是建立在 TCP 協議之上的請求-應答標準。因此,我們將利用 Java 中的 Socket API 來實現這個簡易伺服器。關於 HTTP 協議的更多細節,讀者可自行查閱相關資料深入了解。

HTTP 請求格式分析

在編寫伺服器之前,我們先透過實際代碼觀察瀏覽器發送的請求內容。使用 ServerSocket 監聽 80 埠,接受連接並讀取輸入流:

import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import org.junit.Test;

public class HQHttpProtocolTest {
    @Test
    public void server() throws Exception {
        ServerSocket serverSocket = new ServerSocket(80);
        Socket socket = serverSocket.accept();
        InputStream stream = socket.getInputStream();
        int r = -1;
        while ((r = stream.read()) != -1) {
            System.out.print((char) r);
        }
    }
}

啟動測試後,在瀏覽器訪問 https://127.0.0.1,控制台將輸出類似如下的請求報文:

GET / HTTP/1.1
Host: 127.0.0.1
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36
Accept-Encoding: gzip,deflate,sdch
Accept-Language: zh-CN,zh;q=0.8

為了更全面地分析,我們構造一個包含表單提交的 HTML 頁面,再次觀察請求:

POST /?test=123 HTTP/1.1
Host: 127.0.0.1
Connection: keep-alive
Content-Length: 8
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Origin: null
User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip,deflate,sdch
Accept-Language: zh-CN,zh;q=0.8

name=bob

請求報文結構解析

  • 請求行:由三部分組成,以空格分隔——請求方法(GET/POST)、請求路徑與查詢參數、HTTP 協議版本(HTTP/1.1)。
  • 請求頭:第 2 行至第 10 行,每行格式為 名稱: 值,以 \r\n 分隔。
  • 空行:第 11 行,標誌請求頭結束。
  • 請求體:第 12 行,提交的表單數據(如 name=bob)。

注意:以上僅模擬最簡單的表單提交(application/x-www-form-urlencoded),複雜的文件上傳(multipart/form-data)格式有所不同,本文不展開討論。

HTTP 響應格式分析

同樣地,我們編寫客戶端代碼向一個真實的 Web 伺服器發送請求,捕獲響應報文:

@Test
public void client() throws Exception {
    Socket socket = new Socket("127.0.0.1", 80);
    BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
    writer.write("GET /Servlet/test.html HTTP/1.1\r\n");
    writer.write("Host: 127.0.0.1\r\n");
    writer.write("Connection: keep-alive\r\n");
    writer.write("Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\r\n");
    writer.write("User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36\r\n");
    writer.write("Accept-Encoding: gzip,deflate,sdch\r\n");
    writer.write("Accept-Language: zh-CN,zh;q=0.8\r\n");
    writer.write("\r\n");
    writer.flush();
    InputStream stream = socket.getInputStream();
    int r = -1;
    while ((r = stream.read()) != -1) {
        System.out.print((char) r);
    }
}

伺服器返回的響應內容如下:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Accept-Ranges: bytes
ETag: W/"129-1456125361109"
Last-Modified: Mon, 22 Feb 2016 07:16:01 GMT
Content-Type: text/html
Content-Length: 129
Date: Mon, 22 Feb 2016 08:08:32 GMT

this is test page.

響應報文結構解析

  • 狀態行:HTTP 版本、狀態碼(200)、狀態描述(OK),以空格分隔。
  • 響應頭:第 2 行至第 7 行,格式同請求頭。
  • 空行:第 8 行,分隔頭部與實體內容。
  • 響應體:第 9 行起,實際返回的 HTML 內容。

注意:除此類標準響應外,還存在 Transfer-Encoding: chunked 等分塊傳輸方式,本文不深入探討。

小結

至此,我們已詳細分析了 HTTP 請求與響應的報文格式。下一篇將開始逐步實現伺服器端的核心邏輯,敬請期待。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved