初探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的性能测试工具。。猴了~各位晚安

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