一直以來有對http很多不明白的地方。請教了很多人,自己也做了不少的測試。在此貼上我的心得。有磚望輕拍。
源碼:
package socket;
import java.io.*;
import java.net.*;
public class MyServer {
public static void main(String[] args) throws IOException{
ServerSocket svrSocket = new ServerSocket(80);
Socket socket = svrSocket.accept();
//buffer
byte[] buf = new byte[1024*1024];
InputStream in = socket.getInputStream();
//request ip
System.out.println(socket.getInetAddress());
int byteRead = in.read(buf, 0, 1024*1024);
String dataString = new String(buf, 0, byteRead);
//request
System.out.println(dataString);
PrintWriter p = new PrintWriter(socket.getOutputStream());
//important . something is different with safari
StringBuilder sb = new StringBuilder("HTTP/2.0 200 NOT-OK\r\n")
.append("Host: localhost\r\n")
.append("User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:31.0) Gecko/20100101 Firefox/31.0\r\n")
.append("Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n")
.append("Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n")
.append("Accept-Encoding: gzip, deflate\nConnection: keep-alive\r\n")
.append("Cache-control: no-cache\r\n")
//useful
.append("\r\n");
//header
p.write(sb.toString().toCharArray());
//body
p.write("hello");
p.flush();
in.close();
svrSocket.close();
/*寫法有些非標準的地方*/
}
}
這兒就使用socket啓動了一個服務器了。並且,它是可以被看做http服務器的。在瀏覽器裏面訪問:
看firbug裏面的請求和響應(分別對應了上面console裏面打印的和代碼裏面所寫的)
再看看iptool的截取
瀏覽器發送請求http請求沒有指定的話默認GET.
不難看出這是TCP請求。三次握手完畢之後瀏覽器發送請求數據。等待服務器響應。因爲是keep-alive,每隔一段時間服務器與瀏覽器相互發送確認在線信息。因此咱們需要關注的就是請求和響應的了:
最後那14忘記是幹嘛的了,但是他沒有被包含在這個http請求裏邊:
因此: http請求數據,就這些,不能再多了:
GET / HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:31.0) Gecko/20100101 Firefox/31.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
下面看看服務器反饋的信息,結合着請求信息,就更加容易看明白了:
StringBuilder sb = new StringBuilder("HTTP/2.0 200 NOT-OK\r\n")
.append("Host: localhost\r\n")
.append("User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:31.0) Gecko/20100101 Firefox/31.0\r\n")
.append("Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n")
.append("Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3\r\n")
.append("Accept-Encoding: gzip, deflate\nConnection: keep-alive\r\n")
.append("Cache-control: no-cache\r\n")
//useful
.append("\r\n");
//header
p.write(sb.toString().toCharArray());
//body
p.write("hello");
蘋果的safari對這部分做了重寫,這個更容易被看到:
總結:
①HTTP協議是一個應用層的協議,具體怎麼發,還得交給TCP和IP協議再遞交給物理層去發送。
②不管什麼設備,使用了HTTP協議發送就的遵循他的規範,它也會將發送者的數據封裝成HTTP請求再來發送至於加密(https)或者是保持鏈接(keep-alive)等,又是在它的特性或者是在它上面做了修改了的。
③向一個設備發送一個HTTP請求,只要對方支持HTTP則這個連接就是HTTP連接,它滿足HTTP的各項特性。哪怕是對方回饋的數據並沒交由HTTP封裝工具(常用的tomcat或者apache或者IIS,封裝成標準的HTTP報文)去封裝而是對方自己封裝的(剛剛我做的封裝,電腦firefox能讀出,安卓UC能讀出,蘋果safari就是讀不出),這個回饋還是HTTP RESPONSE。