You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
192 lines
12 KiB
192 lines
12 KiB
# 学习Servlet和Tomcat
|
|
|
|
## 前置任务:了解学习HTTP
|
|
|
|
如果你选了网络工程导论这门课,并且已经了解了HTTP相关的知识,则可以跳过本节,直接开主线任务:[传送点](####Teleport1),但是也可以重新开始学习这部分的内容。
|
|
|
|
想了解更多:[HTTP | MDN](https://developer.mozilla.org/zh-CN/docs/Web/HTTP)
|
|
|
|
### HTTP介绍
|
|
|
|
超文本传输协议(HyperText Transfer Protocol,HTTP)是一个应用层协议。所谓协议,就是数据传输格式的一个约定。
|
|
|
|
HTTP最初设计是用来传输html页面这种纯文本数据的,但是实际上只要声明好header,传输什么都是可以的,图片,文件等等,或者也可以摇身一变,变成另一个协议(grpc, 基于http2)来使用,总之,http其实是非常灵活的。
|
|
|
|
### HTTP消息
|
|
|
|
一个规范的,完整的HTTP消息结构是这样的:
|
|
|
|
请求(GET方法):
|
|
地址:`https://github.com`
|
|
|
|
```http
|
|
GET / HTTP/1.1
|
|
Host: github.com
|
|
authority: github.com
|
|
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.7
|
|
accept-language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
|
|
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.35
|
|
content-length: 0
|
|
|
|
|
|
```
|
|
|
|
请求(POST方法,带请求体):
|
|
|
|
地址:`http://bkjx.wust.edu.cn/Logon.do?method=logon`
|
|
|
|
```http
|
|
POST /Logon.do?method=logon HTTP/1.1
|
|
Host: bkjx.wust.edu.cn
|
|
Proxy-Connection: Keep-Alive
|
|
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.7
|
|
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
|
|
Cache-Control: no-cache
|
|
Connection: keep-alive
|
|
Content-Type: application/x-www-form-urlencoded
|
|
Cookie: bzb_njw=303511D07EF501147333F6B099D16CB9; SERVERID=122
|
|
Origin: http://bkjx.wust.edu.cn
|
|
Pragma: no-cache
|
|
Referer: http://bkjx.wust.edu.cn/
|
|
Upgrade-Insecure-Requests: 1
|
|
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.35
|
|
Content-Length: 94
|
|
|
|
userAccount=&userPassword=&encoded=dMcs2P8fNag0n1d03f0UVgu02^%^257F^%^25QF^%^25pcs0Ygd4fbgHs69
|
|
```
|
|
|
|
响应(header内容精简过):
|
|
```http
|
|
HTTP/1.1 200 OK
|
|
Server: GitHub.com
|
|
Date: Sat, 13 May 2023 02:59:34 GMT
|
|
Content-Type: text/html; charset=utf-8
|
|
Vary: X-PJAX, X-PJAX-Container, Turbo-Visit, Turbo-Frame, Accept-Language, Accept-Encoding, Accept, X-Requested-With
|
|
content-language: en-US
|
|
ETag: W/"bfeda72459b363617514a4f13882cece"
|
|
Set-Cookie: _octo=GH1.1.496438640.1683116779; Path=/; Domain=github.com; Expires=Mon, 13 May 2024 02:59:39 GMT; Secure; SameSite=Lax
|
|
Accept-Ranges: bytes
|
|
Transfer-Encoding: chunked
|
|
|
|
```
|
|
|
|
请求和响应的消息体长得还挺像的,估计大家都能看出来了。
|
|
|
|
#### 第一行 -『起始行』与『状态行』
|
|
|
|
http请求消息中,第一行为『起始行』:
|
|
- `GET / HTTP/1.1`
|
|
- `GET /background.png HTTP/1.0`
|
|
- `POST /Logon.do?method=logon HTTP/1.1`
|
|
|
|
起始行分为三个部分,分别定义了请求方法,请求目标和当前请求使用的http协议版本
|
|
|
|
第一个部分为『[请求方法](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Methods)』,一般有GET, POST, OPTIONS, PUT等好多种,但是实际使用几乎就只有GET和POST两种。
|
|
|
|
随后紧接着的部分是『请求目标』,在普通的http请求中也可以简单理解为请求路径,也就是咱们看到的浏览器地址后面的部分(xxx.com/abcd/efg中的/abcd/efg,bkjx.wust.edu.cn/Logon.do?method=logon中的/Logon.do?method=logon部分)
|
|
|
|
在部分场合下,请求目标有时也是一个绝对路径的URL,如当使用HTTP代理访问网站时,浏览器向代理服务器(如软件)发送的数据也是一个http请求,只不过真实的请求放在了body部分,代理程序只负责原样发送数据:`CONNECT google.com:443 HTTP/1.1`
|
|
|
|
这里就抄一下MDN的介绍:
|
|
|
|
> - 一个绝对路径,末尾跟上一个 '?' 和查询字符串。这是最常见的形式,称为原始形式(origin form),被 GET、POST、HEAD 和 OPTIONS 方法所使用。
|
|
> - - POST / HTTP/1.1
|
|
> - - GET /background.png HTTP/1.0
|
|
> - - HEAD /test.html?query=alibaba HTTP/1.1
|
|
> - - OPTIONS /anypage.html HTTP/1.0
|
|
> - 一个完整的 URL,被称为绝对形式(absolute form),主要在使用 GET 方法连接到代理时使用。GET http://developer.mozilla.org/en-US/docs/Web/HTTP/Messages HTTP/1.1
|
|
> - 由域名和可选端口(以 ':' 为前缀)组成的 URL 的 authority 部分,称为 authority form。仅在使用 CONNECT 建立 HTTP 隧道时才使用。CONNECT developer.mozilla.org:80 HTTP/1.1
|
|
> - 星号形式(asterisk form),一个简单的星号('*'),配合 OPTIONS 方法使用,代表整个服务器。OPTIONS * HTTP/1.1
|
|
|
|
最后的一部分为『HTTP版本』,声明了这次请求使用的http版本。目前常用的版本有`HTTP/1.1`,`HTTP/2`,`HTTP/3`。
|
|
|
|
> 另外,和其他HTTP版本不同的是,HTTP/3版本是在基于UDP的QUIC协议之上实现传输的,QUIC是与TCP和UDP等同级(传输层)的协议,而其他的HTTP版本都是在TCP协议上实现的,
|
|
|
|
对于响应消息,第一行为『状态行』。
|
|
- `HTTP/1.1 200 OK`
|
|
- `HTTP/1.1 404 Not Found`
|
|
- `HTTP/1.1 500 Internal Server Error` **(心 脏 骤 停)**
|
|
|
|
也是三个部分。
|
|
|
|
响应的状态行就挺简单的了。
|
|
|
|
第一个就不用说了。
|
|
|
|
第二个则为『状态码』,就是咱们常见的404, 200这些,表明了服务端处理请求的结果状态。
|
|
|
|
第三个部分则为『状态文本』,其实就是状态码的描述。
|
|
|
|
有哪些状态码,可以[自行了解了解](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status),最好记得一些常用的状态码的含义,要是乱抛状态码给前端有的是一顿毒打(
|
|
|
|
当然,在许多场合中,业务状态(成功,认证错误,参数错误等等)一般并不通过状态码表示,而是200响应,在响应消息体里边体现错误;但是也有状态码和消息体都体现的情况。具体还是要跟前端和客户端的小伙伴商量约定好规范和文档,按照团队的规范和文档行事,能少很多不必要的麻烦。
|
|
|
|
#### 『标头』(Header)
|
|
|
|
请求和响应的消息体过了第一行之后,就到了『标头』(header)部分了,一般咱们把这玩意叫『请求头』和『响应头』。
|
|
|
|
http消息的header实际上就是一个键值对,格式为`Key: Value`,一行一个
|
|
|
|
需要注意的是,这里的key是不分大小写的,例如`Host`,`host`,`HOST`,`hOST`都是同一个东西。
|
|
|
|
同一个key的Header也可以有多个值,因此,在各种http库中,获取到的header值都是一个List<String>。
|
|
|
|
比如:
|
|
```
|
|
Set-Cookie: logged_in=no; Path=/; Domain=github.com; Expires=Mon, 13 May 2024 02:59:39 GMT; HttpOnly; Secure; SameSite=Lax
|
|
Set-Cookie: access_token=abcdefg; Path=/; Domain=github.com; Expires=Mon, 13 May 2024 02:59:39 GMT; Secure; SameSite=Lax
|
|
```
|
|
|
|
虽然如此,但是除非有必要(例如上面的例子中给客户端返回Cookie),在响应或者请求的时候最好不要这么干,即使可以这么干,否则在对方处理的时候会很麻烦。
|
|
|
|
一般来说,咱们会经常见到这些请求头或者响应头:
|
|
> - `Host`: 请求的目标主机,通常是在同一个ip和端口上有多个不同的服务时,提供给nginx或者apache等类似的其他的反代网关判断究竟应该执行哪个配置块时使用的。
|
|
> - `User-Agent`: 表明请求客户端信息,一般格式为`程序名/版本`,当然,也可以添加其他额外的信息,如firefox的ua:`Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/111.0`
|
|
> - `Content-Type`: 请求/响应传输数据的类型,即下一节中body部分数据的格式。按照规范,这个字段的值应该使用MIME type格式,这里是一些[常用的MIME类型](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types)。
|
|
> - `Accept`: 能接受的数据格式,一般为用逗号`,`分隔开的若干个MIME type格式
|
|
> - `Accept-Encoding`: 指定能够接受的响应数据编码,和`Accept`不同的是,`Accept`指定的是body部分的数据格式,但是这里指定的是整个响应的数据编码,通常是压缩算法,如`gzip, deflate, br`,设置了这个值后,如果服务端支持,响应的时候会对整个HTTP消息进行相应的压缩后,再返回响应给客户端,客户端需要进行解压解码后再进行处理。一般http框架和web框架都能自动进行自动的处理。
|
|
> - `Referer`: 说明请求是从哪里来的
|
|
> - `Cookie`: 向服务器请求时附带的一些信息,就是咱们常说的cookie,浏览器在请求的时候如果有相对应的Cookie,会自动附带上这些Cookie进行请求。
|
|
> - `Set-Cookie`: 服务端响应回来的Cookie,浏览器看到这个header之后就会根据这个header的值去保存cookie到浏览器里边。下次请求cookie对应规则的地址时会自动附带这些信息,即上一条中的Cookie字段。
|
|
|
|
Cookie一般用于用户的识别和身份认证以及一些额外信息的保存。[了解更多关于Cookie的东西](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Cookies)
|
|
|
|
实际上,很多header值只是作为一个参考,作为后端开发,不应该过于信赖前端/客户端发来的数据,后端程序必须要对前端/客户端做充足的数据校验,如`Content-Type`,前端/客户端可以在请求的时候在`Content-Type`字段里说他发了`image/png`图片,但是可能实际上发来的数据是一个程序,如果不做任何校验直接保存到服务器上,那可就麻烦大了。
|
|
|
|
一般来说,很多http请求和web服务框架都能帮咱们写好这些通用的请求头和响应头,不用咱们过于操心,当然,如果有需求更改的话也能更改好。
|
|
|
|
这里对header的作用描述不一定十分的准确,可以查看相关的文档了解详细详情:[HTTP 标头(header)](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers),Ctrl+F直接一搜就到
|
|
|
|
#### 『主体』(body)
|
|
|
|
在前面的header定义完之后,需要各一行空行,才到http消息中的『主体』部分。
|
|
|
|
这个body部分就是这个请求真正想要传输的数据。
|
|
|
|
这部分可以是纯文本,也可以是二进制,都行,只要Content-Type说好了就行,没说的话,一般也行,但是得看后端处不处理了,一些后端框架不会帮你自动判断Body格式,或者不同的Content-Type处理的方式不同,如果请求的时候没有设置对,可能会有些麻烦事。
|
|
|
|
> 另外,上面的起始行/状态行和header行以及body和上面几行中间间隔的空行,和windows一样,使用的换行符都为CRLF,也就是`\r\n`,而不是linux/unix常用的`\n`。当然,这个知道就好了,库会帮咱们处理好的。
|
|
|
|
### HTTPS
|
|
|
|
HTTPS就是加密后的HTTP,'S'就是"Secure"。一般使用TLS来加密。原始的http消息经过全部加密后,再进行传输。只要中间偷听的人拿不到密钥,就不可能知道除了请求的ip以外任何的http信息。
|
|
|
|
关于现代TLS加密的机制,可以去看看[这篇文章](https://zhuanlan.zhihu.com/p/43789231)
|
|
|
|
一般约定http跑在80端口上,而https跑在443端口上,但是也可以用其他端口。
|
|
|
|
我的建议是,https能上就上。
|
|
|
|
#### Teleport1
|
|
|
|
## 主线任务:Servlet,Tomcat
|
|
|
|
## Servlet
|
|
|
|
在开始Tomcat的学习之前,咱们先要了解Servlet。 |