1.1 简述
浏览器在访问一个IP地址的时候,一般会自动在地址前方加上HTTP:// 表示其基于http协议访问。
一般而言,http跟tcp在本质上没有区别。
tcp连接的过程,在JAVA语言中,在java.net包中被集成,可以很方便的调用。
Socket s = new Socket("IP地址",端口号);
tcp连接的确立基于三次握手,其过程本质上是C端与S端相互验证,建立信任的一种方式。http跟tcp在网络通信中所属的层级不同,但http协议大致是在tcp基础上,需要额外一些相互验证,建立信任的方式,以满足http协议的需要。如同tcp协议链接过程的三次握手一般,http也有一套固定的验证格式。
因此,使用Socket类,在此基础之上将其固定的验证格式实现,将C端请求的内容以一定格式解析,将响应内容以一定格式包装,便可以实现响应http请求。
1.2 大致的结构
如图,一个HTTP请求与响应的流程大致如此
1、浏览器端向服务器发送一个http请求,其数据由服务器端一个基于Socket协议的接收器接收。
2、接收器将接收到的数据交由一内容解析器解析,以获取该http请求的请求内容。
3、解析器将解析出来的内容交由业务处理器,业务处理器负责根据请求生成响应的内容,其可以是一个html页面,可以是一张图片,也可以是一段代码块,之后将内容交由包装器。
4、包装器将内容包装成http响应的相应格式。
5、基于Socket协议的发送器将包装好的内容发送给浏览器。
其中浏览器的部分自然不需要我们实现,而Socket的部分直接使用java.net中现成的东西,构建一个能响应http请求的服务器,所需要实现的是:
1、HTTP请求内容解析器
2、HTTP响应内容包装器
3、业务处理部分。
1.3 HTTP请求内容解析器
创建一个Socket
ServerSocket ss = new ServerSocket(8888);
Socket s = ss.accept();
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String str = null;
while ((str = br.readLine()) != null) {
System.out.println(str);
}
br.close();
s.close();
ss.close();
使用本地浏览器访问一次,便可获得http响应中包含的内容:
GET / HTTP/1.1
Host: localhost:8888
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
其中包含的内容有访问的方式,HTTP协议的版本,可以返回的数据格式,浏览器的信息等。
先考虑GET方式,一般而言,http的C端,其期望执行的业务,以参数的形式,通过HTTP协议内容进行传递。
在访问地址后面加上请求的业务参数和其他社么东西。
GET /login.html?username=gaga HTTP/1.1
Host: localhost:8888
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
发现URL中的Path部分被完整的添加到了http请求中的第一行。
也就是说,如果业务参数仅包含URL中的内容(不考虑不同的浏览器或者啥),HTTP请求内容解析器所需要解析的东西,仅包括http请求中的第一行。
1.4 HTTP响应内容包装器
http响应格式必须遵循http响应的格式,其包括响应体和响应头两部分,中间以一个换行符分隔。
其中响应头的第一行必须遵循HTTP版本+响应状态+响应状态描述的格式组成。其他就没什么要求了。
最简单的一响应格式比如
PrintStream ps = new PrintStream(s.getOutputStream());
ps.println("HTTP/1.1 200 OK");
ps.println();
ps.write("你好".getBytes());
其执行的结果: