HTTP协定
HTTP协定 超文本传输协定 由万维网制订(w3c)
是浏览器与服务器通信的应用层协定,规定了浏览器与服务器之间的交互规定以及交互数据的
格局信息等。
HTTP协定对应客户端与服务端之间的交互规定有以下定义:
要求浏览器与服务端之间必须遵循一问一答的规定,即:浏览器与服务端建设TCP连贯后须要
先发送一个申请(问)而后服务端接管到申请并予以解决后再发送响应(答)。留神,服务端永远
不会被动给浏览器发送信息。
HTTP要求浏览器与服务端的传输层协定必须是牢靠的传输,因而是应用TCP协定作为传输层
协定的。
HTTP协定对于浏览器与服务器之间交互的数据格式,内容也有肯定的要求。
浏览器给服务端发送的内容称为申请 Request
服务端给浏览器发送的内容称为响应 Response
申请和响应中大部分内容 都是文本信息(字符串)。并且这些文本数据应用的字符集为:
ISO8859-1.这是一个欧洲的字符集 ,外面是不反对中文的!!而实际上申请和响应呈现
的字符也就是英文、数字、符号。
申请Request
申请是浏览器发送给服务端的内容,HTTP协定中一个申请由三局部形成:
别离是:申请行,音讯头,音讯注释。 音讯注释局部能够没有。
1:申请行
申请行是一行字符串,以间断的两个字符(回车符和换行符)作为完结这一行的标记。
回车符:在ASC编码中2进制内容对应的整数是13.回车符通常用cr示意。
换行符:在ASC编码中2进制内容对应的整数是10.换行符通常用lf示意。
回车符和换行符实际上都是不可见字符。
申请行分为三局部:
申请形式(SP)形象门路(SP)协定版本(CRLF) 注:SP是空格
GET /index.html HTTP/1.1
2:音讯头
音讯头是浏览器能够给服务端发送的一些附加信息,有的用来阐明浏览器本身内容,有的用来告知服务端交互细节,有的告知服务端音讯注释详情等。
音讯头由若干个组成,每行完结也是以CRLF标记。
每个音讯头的格局为:音讯头的名字(:SP)音讯的值(CRLF)
音讯头局部完结是以独自的(CRLF)标记。
例如:
GET /index.html HTTP/1.1
Host: localhost:8088
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/79.0.3945.130 Safari/537.36
Sec-Fetch-User: ?1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
一、第一版
WebServer Web容器,模仿Tomcat的根底性能
Web容器的主要职责是
1:治理上面所有部署的webapp(web利用)每一个web利用都会蕴含本人的网页,资源,对应的业务代码(java代码,解决逻辑的)因而一个web利用能够看作是一个“网站”
2:与客户端(通常就是浏览器)维持TCP的连贯以及基于HTTP协定的交互,使得浏览器能够通过网络拜访某个web利用的性能。
public class WebServer {
private ServerSocket server;
public WebServer(){
try{
System.out.println("正在启动服务端...");
server = new ServerSocket(8088);
System.out.println("启动服务端结束!");
}catch(Exception e){
e.printStackTrace();
}
}
public void start(){
try {
System.out.println("期待客户端连贯...");
Socket socket = server.accept();
System.out.println("一个客户端连贯了!");
InputStream in = socket.getInputStream();
int d=0;
while((d= in.read())!=-1){
System.out.println((char)d);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
WebServer server = new WebServer();
server.start();
}
}
二、第二版
本版本次要测试从申请中读取一行字符串的操作
一个申请中的申请行和音讯头有一个共同点,都是以CRLF结尾的一行字符串。因而实现了
读取一行字符串的操作后就能够复用他来实现解析申请行和音讯头的工作。
因为服务端要解决多客户端,所以依然应用线程解决客户端的交互:ClientHandler。
实现:
1:在com.webserver.core包下新建类:ClientHandler
2:在WebServer中接管客户端连贯后启动线程
3:在ClientHandler中实现测试读取一行字符串的操作
三、第三版
本版本进行对申请的解析工作
思路:
设计一个类:HttpRequet,使这个类的每一个实例示意浏览器发送过去的一个具体申请内容
这个类中设计若干属性,别离示意一个申请中的各项信息。这样一来当咱们读取一个申请内容
后用一个HttpRequest示意后,能够通过获取该对象的属性值来获取对应的信息便于后续解决
申请的工作。
实现:
1:创立一个新的包:com.webserver.http
在这个包中保留所有和HTTP无关的类
2:在http包中创立HttpRequest 即:申请对象
3:实现HttpRequest的性能
4:在ClientHandler中第一个环节解析申请时实例化HttpRequest,实现解析申请。
四、第四版
实现ClientHandler解决申请的环节
用户在浏览器上输出地址如:
http://localhost:8008/myweb/index.html
心愿申请对应的页面,解决环节在作用就是依据用户申请的地址寻找这个文件,而后依据是否
找的做分支解决,以便后续第三步响应客户端时的操作。
实现:
1:在我的项目目录下新建一个目录webapps,用这个目录存所有部署的网络应用。每个网络应用以
一个子目录模式保留,并且目录名就是这个利用的名字。
2:在webapps目录下新建第一个子目录myweb作为咱们第一个网络应用。
3:在myweb目录下新建高利用中的第一个页面:index.html
4:用户在浏览器申请如下门路:
http://localhost:8088/myweb/index.html
ClientHandler增加第二步解决申请的工作
4.1首先从request对象中获取申请的形象门路,
即:uri属性的值。该值该当为:/myweb/index.html
4.2依据这个值创立一个File从"./webapps"目录下绝对该uri的值找到对应文件
并通过判断该文件是否存在定义好分支。
五、第五版
此版本开始实现响应客户端的工作
上一个版本中咱们曾经在ClientHandler中增加分支,这里先实现资源已找到的响应过程。
此时咱们该当将该资源已一个规范的HTTP响应格局发送给客户端使其展现该资源。
实现:
在ClientHandler的找到资源的分支中,通过socket获取输入流,发送一个响应并测试资源
存在的状况浏览器是否正确显示。
六、第六版
此版本持续开始实现响应客户端的工作
上一个版本中咱们曾经将用户申请的资源响应了,本版本咱们来实现如果资源不存在时响应
404页面的工作。
实际上当用户申请的资源不存在,那么服务端发送的响应中状态代码为404,用来告知浏览器
申请的门路有效。并能够同时响应一个404页面进行展现。
实现:
1:在webaaps目录下新建一个目录root
2:在root目录下新建页面:404.html
转让给页面中只须要居中显示一行字:404!资源不存在!
注:该页面没有放在myweb目录下,而是放在root目录下的起因是无论用户未来申请哪个
网络应用下的资源都可能存在着资源没有找到的状况,因而响应404这个页面是一个
通用操作,所有未来把所有通用的页面放在root下共用即可。
3:在ClientHandler解决申请环节中资源不存在的分支里,响应404.
状态行内容为;HTTP/1.1 404 NOT FOUND
响应头不变,还是Content-type与Content-Length,留神,长度该当是404页面的长度
响应注释则是将404页面的内容发送到客户端。
启动程序后做如下测试:
http://localhost:8088/myweb/indes.html 注:index1.html在myweb目录下没有
此时该当能看到404页面显示在浏览器中