初探HTTP協議 原

1.公司現在比較多使用WebSocket, WebSocket又是Http通過101協議升級連接的,所以先探究下HTTP的交流過程,用TCP去實現HTTP。下一個博客將會嘗試用TCP去實現WebSocket。純粹是一個個人成長記錄,如果大神看到哪裏有問題請多多指點,不過目測大神應該不會點開這條博客。

2.首先,在我小時候玩易語言曾經試過啓動一個socket服務,然後在瀏覽器訪問時發現一些特別的東西。就是那一串

GET / HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36 Qiyu/1.1.2.0
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8

到了現在對各種東西慢慢開始熟悉後,回想起這段經歷,大致猜測HTTP就是用Socket發送特定文本去交流,先貼出人人都會的Java代碼

public static void main(String[] args) {
        try {
            ServerSocket server = new ServerSocket(8080);
            while (true) {
                Socket socket = server.accept();
                if(null != socket) {
                    InputStream inputStream = socket.getInputStream();
                    InputStreamReader reader = new InputStreamReader(inputStream);
                    char[] chars = new char[5000];
                    reader.read(chars);
                    System.out.println(chars);
                    reader.close();
                    socket.close();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

啓動後在瀏覽器訪問localhost:8080 就會得到最上面那串http協議了。現在我們複製這段協議對瀏覽器請求進行響應。對代碼進行修改

 public static void main(String[] args) {
        try {
            ServerSocket server = new ServerSocket(8080);
            while (true) {
                Socket socket = server.accept();
                if(null != socket) {
                    InputStream inputStream = socket.getInputStream();
                    InputStreamReader reader = new InputStreamReader(inputStream);
                    char[] chars = new char[5000];
                    reader.read(chars);
                    String httpProtocol = new StringBuilder("GET / HTTP/1.1\n")
                            .append("Host: localhost:8080\n")
                            .append("Connection: keep-alive\n")
                            .append("Cache-Control: max-age=0\n")
                            .append("Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\n")
                            .append("Upgrade-Insecure-Requests: 1\n")
                            .append("User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.80 Safari/537.36 Qiyu/1.1.2.0\n")
                            .append("Accept-Encoding: gzip, deflate, sdch\n")
                            .append("Accept-Language: zh-CN,zh;q=0.8\n").toString();
                    OutputStreamWriter writer = new OutputStreamWriter(socket.getOutputStream());
                    writer.write(httpProtocol);
                    writer.flush();
                    reader.close();
                    writer.close();
                    socket.close();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

然而這個瀏覽器原樣返回,這不是因爲你對了,而是錯了。 稍微對HTTP有點了解的都知道HTTP Request和Response是不一樣的,那我們應該怎樣知道Response的Header應該有些什麼呢。這個很簡單。Chrome的F12 -> Network。至於其他瀏覽器就自行百度了。

現在想找個簡單點的請求都難啊。我是做APP後臺的,就直接拿公司APP捉個包看一下吧。

HTTP/1.1 200 OK
Server: Tengine/2.1.2
Date: Thu, 03 Nov 2016 16:13:35 GMT
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive

確實真夠簡單的,測試一下先

這次我們看到的是一個空頁面,這次就對了, 由於我們Response Body並沒有東西,所以顯示空白就證明瀏覽器已經受到我們的空白返回了。

由於我抓的是APP服務端的包,所以返回的是JSON,那我們就直接換一個行返回一個簡單的JSON試試

public static void main(String[] args) {
        try {
            ServerSocket server = new ServerSocket(8080);
            while (true) {
                Socket socket = server.accept();
                if(null != socket) {
                    InputStream inputStream = socket.getInputStream();
                    InputStreamReader reader = new InputStreamReader(inputStream);
                    char[] chars = new char[5000];
                    reader.read(chars);
                    System.out.println(chars);
                    String httpProtocol = new StringBuilder("HTTP/1.1 200 OK\n")
                            .append("Server: Tengine/2.1.2\n")
                            .append("Date: Thu, 03 Nov 2016 16:13:35 GMT\n")
                            .append("Content-Type: application/json;charset=UTF-8\n")
                            .append("Transfer-Encoding: chunked\n")
                            .append("Connection: keep-alive\n")
                            .append("{\"abc\",123}").toString();
                    OutputStreamWriter writer = new OutputStreamWriter(socket.getOutputStream());
                    writer.write(httpProtocol);
                    writer.flush();
                    reader.close();
                    writer.close();
                    socket.close();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

瀏覽器顯示的仍然是空白.看看剛捉的數據包,有兩個換行~那我們再加一個換行試試。 喲,顯示”無法顯示此網頁“了

在捉包的數據發現header兩個換行後有一個f6c 加上後果然就再次顯示空白了。但是並沒有達到預期的效果。但是瀏覽器的請求狀態一直顯示failed...搞了一堆堆原來和

Transfer-Encoding: chunked

這句有關係。這個屬性的解釋詳見:https://imququ.com/post/transfer-encoding-header-in-http.html

到了這裏我們就可以實現一個簡單的Web容器了。至於HTTP的屬性我也不一一介紹出來。一百度就一大堆,不過最好還是看HTTP RFC文檔,看了一些文章發現,用telnet能更好地觀察HTTP協議的傳輸。總算學到東西了。  在這給大家推薦一本不錯的書《Tomcat內核剖析》,這本書已經絕版,但是淘寶有十幾塊的印刷版,本人覺得還是可以接受的,有興趣的小夥伴買本來看看吧。

現在是在有點晚了,可憐下我這個996的苦逼。我先睡了明天找個時間試試telnet WebSocket先。然後再實現一個WebSocket客戶端。終極目標是做個WebSocket的性能測試工具。。猴了~各位晚安

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章