1. 万维网
1.1 万维网概述
万维网 WWW (World Wide Web)并非某种特殊的计算机网络
万维网是一个大规模的、联机式的信息储藏所
万维网用链接的方法能非常方便地从因特网上的一个站点访问另一个站点,从而主动地按需获取丰富的信息
这种访问方式称为“链接”
起初是用hao123.com这样的导航页
现在是用baidu这样的搜索引擎来进行关键字搜索找到自己感兴趣的链接
万维网提供分布式服务
1.2 超媒体与超文本
万维网是分布式的超媒体系统,他是超文本系统的扩充
超文本是指包含指向其他文档的链接(超链接)的文本,也就是说,一个超文本由多个信息源构成,而这些信息源可以分布在世界各地,利用一个链接可以使用户找到远在异地的另一个文档(页面)
超媒体与超文本的区别是文档内容不同。超文本文档仅包含文本信息,而超媒体文档还包含其他表示方式的信息,如图形、图像、声音、动画,甚至活动视频图像
1.3 万维网的工作方式
万维网以客户服务器方式工作
浏览器就是在用户计算机上的万维网客户程序。万维网文档所驻留的计算机则运行服务器程序,因此这个计算机也称为万维网服务器
客户程序向服务器程序发出请求,服务器程序向客户程序送回客户所要的万维网文档
在一个客户程序主窗口上显示出的万维网文档称为页面(page)
1.4 万维网需要解决的问题
① 怎么标志分布在整个互联网上的万维网文档 (URL)
使用统一资源定位符 URL (Uniform Resource Locator)来标志万维网上的各种文档。
使每一个文档在整个因特网的范围内具有唯一的标识符 URL
② 用什么样的协议来实现万维网上的各种链接 (HTTP)
在万维网客户程序与万维网服务器程序之间进行交互所使用的协议,是超文本传送协议 HTTP (HyperText Transfer Protocol)。
HTTP 是一个应用层协议,它使用 TCP 连接进行可靠的传送
③ 怎样使各种万维网文档都能在因特网上的各种计算机上显示出来,同时使用户清楚地知道在什么地方存在着超链 (HTML)
超文本标记语言 HTML (HyperText Markup Language)使得万维网页面的设计者可以很方便地用一个超链从本页面的某处链接到因特网上的任何一个万维网页面,并且能够在自己的计算机屏幕上将这些页面显示出来
④ 怎样使用户能够很方便地找到所需的信息 (搜索引擎)
为了在万维网上方便地查找信息,用户可使用各种的搜索工具(即搜索引擎)
2. URL
vs URI
统一资源定位符 URL 是对可以从因特网上得到的资源的位置和访问方法的一种简洁的表示
使用HTTP的URL | http://<主机>:<端口>/<路径> |
① http这表示使用 HTTP 协议
② 冒号和两个斜线是规定的格式
③ 主机的域名
④ HTTP 的默认端口号是 80,通常可省略
⑤ 若再省略文件的<路径>项,则 URL 就指到因特网上的某个主页(home page)
URI:Uniform Resource Identifier 统一资源标识符
URI 是用来标示 一个具体的资源的,我们可以通过 URI 知道一个资源是什么
3. 超文本传输协议HTTP
3.1 HTTP的操作过程
HTTP协议定义了浏览器(即万维网客户进程)怎么向万维网服务器请求万维网文档以及服务器怎么把文档传送给浏览器
从层次的角度看,HTTP 是面向事务的(transaction-oriented)应用层协议,它是万维网上能够可靠地交换文件(包括文本、声音、图像等各种多媒体文件)的重要基础
(1) 浏览器分析超链指向页面的 URL。
(2) 浏览器向 DNS 请求解析 www.tsinghua.edu.cn
的 IP 地址。
(3) 域名系统 DNS 解析出清华大学服务器的 IP 地址。
(4) 浏览器与服务器建立 TCP 连接
(5) 浏览器发出取文件命令:GET /chn/yxsz/index.html
(6) 服务器给出响应,把文件 index.htm 发给浏览器。
(7) TCP 连接释放。
(8) 浏览器显示“清华大学院系设置”文件 index.htm 中的所有文本
3.2 HTTP的主要特性
1. HTTP 是面向事务的客户服务器协议
所谓事务就是说一些列的信息交换,而这一系列的信息交换是不可分割的整体,也就是说要么所有的信息交换都完成,要么一次交换都不进行
2. HTTP 1.0 协议是无状态的(stateless)
同一个客户第二次访问同一服务器上的页面时,服务器的响应与第一次访问时的相同,他并不知道这个客户以前来过
之所以这样设计是为了简化服务器的设计,使服务器更容易支持大量并发的HTTP请求
无状态其实既是优点又是缺点。因为服务器没有记忆能力,所以就不需要额外的资源来记录状态信息,不仅实现上会简单一些,而且还能减轻服务器的负担,能够把更多的 CPU 和内存用来对外提供服务
但是服务器没有记忆能力,它就无法支持需要连续多个步骤的事务
操作。每次都得问一遍身份信息,不仅麻烦,而且还增加了不必要的数据传输量。由此出现了 Cookie
技术
3. HTTP 协议本身也是无连接的,虽然它使用了面向连接的 TCP 向上提供的服务
虽然HTTP使用面向连接的TCP作为运输层协议,保证了数据的可靠传输,但是HTTP协议本身是无连接的,不用建立HTTP连接
4. 明文
HTTP 协议里还有一把优缺点一体的双刃剑,就是明文传输。明文意思就是协议里的报文(准确地说是 header 部分)不使用二进制数据,而是用简单可阅读的文本形式。
对比 TCP、UDP 这样的二进制协议,它的优点显而易见,不需要借助任何外部工具,用浏览器、Wireshark 或者 tcpdump 抓包后,直接用肉眼就可以很容易地查看或者修改,为我们的开发调试工作带来极大的便利。
当然缺点也是显而易见的,就是不安全,可以被监听和被窥探。因为无法判断通信双方的身份,不能判断报文是否被更改过
5. 应用广泛、环境成熟
因为 HTTP 协议本身不属于一种语言,它并不限定某种编程语言或者操作系统,所以天然具有跨语言、跨平台的优越性。而且,因为本身的简单特性很容易实现,所以几乎所有的编程语言都有 HTTP 调用库和外围的开发测试工具
随着移动互联网的发展, HTTP 的触角已经延伸到了世界的每一个角落,从简单的 Web 页面到复杂的 JSON、XML 数据,从台式机上的浏览器到手机上的各种 APP、新闻、论坛、购物、手机游戏,你很难找到一个没有使用 HTTP 的地方
6. 简单灵活易扩展
HTTP 最重要也是最突出的优点是 简单、灵活、易于扩展
3.3 持续连接vs非持续连接
HTTP协议的基础是下面的运输层建立了TCP连接
HTTP/1.0使用非持续连接
可以看到请求到一次万维网文档所需要的时间是该文档的传输时间+建立TCP连接的时间,在HTTP/10中会为每次请求都建立一个TCP连接,这种非持续连接不仅使请求时间变慢而且让服务器的负担很重
HTTP/1.1使用持续连接
万维网服务器在发送响应后仍然在一段时间内保持这条连接,使同一个客户(浏览器)和该服务器可以继续在这条连接上传送后续的 HTTP 请求报文和响应报文
这并不局限于传送同一个页面上链接的文档,而是只要这些文档都在同一个服务器上就行
目前一些流行的浏览器(例如,IE 6.0)的默认设置就是使用 HTTP/1.1
① 非流水线方式:客户在收到前一个响应后才能发出下一个请求。这比非持续连接的两倍 RTT 的开销节省了建立 TCP 连接所需的一个 RTT 时间。但服务器在发送完一个对象后,其 TCP 连接就处于空闲状态,浪费了服务器资源
② 流水线方式:客户在收到 HTTP 的响应报文之前就能够接着发送新的请求报文。一个接一个的请求报文到达服务器后,服务器就可连续发回响应报文。使用流水线方式时,客户访问所有的对象只需花费一个 RTT时间,使 TCP 连接中的空闲时间减少,提高了下载文档效率
3.4 HTTP 1.0 vs 1.1 vs 1.2
HTTP1.1 的主要变化:
- HTTP1.0 经过多年发展,在 1.1 提出了改进。首先是提出了长连接,HTTP 可以在一次 TCP 连接中不断发送请求。
- 然后 HTTP1.1 支持只发送 header 而不发送 body。原因是先用 header 判断能否成功,再发数据,节约带宽,事实上,post 请求默认就是这样做的。
- HTTP1.1 的 host 字段。由于虚拟主机可以支持多个域名,所以一般将域名解析后得到 host。
HTTP2.0 的主要变化:
- HTTP2.0 支持多路复用,同一个连接可以并发处理多个请求,方法是把 HTTP数据包拆为多个帧,并发有序的发送,根据序号在另一端进行重组,而不需要一个个 HTTP请求顺序到达;
- HTTP2.0 支持服务端推送,就是服务端在 HTTP 请求到达后,除了返回数据之外,还推送了额外的内容给客户端;
- HTTP2.0 压缩了请求头,同时基本单位是二进制帧流,这样的数据占用空间更少;
- HTTP2.0 适用于 HTTPS 场景,因为其在 HTTP和 TCP 中间加了一层 SSL 层。
3.5 代理服务器
代理服务器(proxy server)又称为万维网高速缓存(Web cache),它代表浏览器发出 HTTP 请求。
万维网高速缓存把最近的一些请求和响应暂存在本地磁盘中。
当与暂时存放的请求相同的新请求到达时,万维网高速缓存就把暂存的响应发送出去,而不需要按 URL 的地址再去因特网访问该资源
3.6 HTTP报文结构
3.6.1 请求报文
请求报文——从客户向服务器发送请求报文
请求行
① “方法”是面向对象技术中使用的专门名词。所谓“方法”就是对所请求的对象进行的操作,因此这些方法实际上也就是一些命令。因此,请求报文的类型是由它所采用的方法决定的
请求方式有:POST
、GET
、HEAD
、OPTIONS
、DELETE
、TRACE
、PUT
,常用的有: GET
、 POST
GET | 获取资源,当前网络中绝大部分使用的都是 GET |
HEAD | 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头,用于确认 URI 的有效性及资源更新的日期时间等 |
POST | 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改 |
PUT | 上传文件,由于自身不带验证机制,任何人都可以上传文件,因此存在安全性问题,一般不使用该方法 |
PATCH | 对资源进行部分修改。PUT 也可以用于修改资源,但是只能完全替代原始资源,PATCH 允许部分修改 |
OPTIONS | 查询指定的 URL 支持的方法 |
CONNECT | 要求在与代理服务器通信时建立隧道。使用 SSL(Secure Sockets Layer,安全套接层)和 TLS(Transport Layer Security,传输层安全)协议把通信内容加密后经网络隧道传输 |
TRACE | 追踪路径。服务器会将通信路径返回给客户端。发送请求时,在 Max-Forwards 首部字段中填入数值,每经过一个服务器就会减 1,当数值为 0 时就停止传输。通常不会使用 TRACE,并且它容易受到 XST 攻击(Cross-Site Tracing,跨站追踪) |
post和get的区别:
- 都包含请求头请求行 post多了请求bod
- get多用来查询,请求参数放在url中,不会对服务器上的内容产生作用
- post用来提交,如把账号密码放入body中
- GET是直接添加到URL后面的,直接就可以在URL中看到内容,而POST是放在报文内部的,用户无法直接看到
- GET提交的数据长度是有限制的,因为URL长度有限制,具体的长度限制视浏览器而定。而POST没有
② “URL”是所请求的资源的 URL
③ “版本”是 HTTP 的版本。
消息头
accept | 浏览器通过这个头告诉服务器,它所支持的数据类型 |
Accept-Charset | 浏览器通过这个头告诉服务器,它支持哪种字符集 |
Accept-Encoding | 浏览器通过这个头告诉服务器,支持的压缩格式 |
Accept-Language | 浏览器通过这个头告诉服务器,它的语言环境 |
Host | 浏览器通过这个头告诉服务器,想访问哪台主机 |
If-Modified-Since | 浏览器通过这个头告诉服务器,缓存数据的时间 |
Referer | 浏览器通过这个头告诉服务器,客户机是哪个页面来的 防盗链 |
Connection | 浏览器通过这个头告诉服务器,请求完后是断开链接还是何持链接 |
Cache-Control | 控制缓存行为 |
3.6.2 响应报文
响应报文——从服务器到客户的回答。
常见状态码:
以 2xx
为开头的都表示请求成功响应
状态码 | 含义 |
---|---|
200 | 成功响应 |
204 | 请求处理成功,但是没有资源可以返回 |
206 | 对资源某一部分进行响应,由Content-Range 指定范围的实体内容 |
以 3xx
为开头的都表示需要进行附加操作以完成请求
状态码 | 含义 |
---|---|
301 | 永久性重定向,该状态码表示请求的资源已经重新分配 URI,以后应该使用资源现有的 URI |
302 | 临时性重定向。该状态码表示请求的资源已被分配了新的 URI,希望用户(本次)能使用新的 URI 访问 |
303 | 该状态码表示由于请求对应的资源存在着另一个 URI,应使用 GET 方法定向获取请求的资源 |
304 | 该状态码表示客户端发送附带条件的请求时,服务器端允许请求访问资源,但未满足条件的情况 |
307 | 临时重定向。该状态码与 302 Found 有着相同的含义 |
以 4xx
的响应结果表明客户端是发生错误的原因所在
状态码 | 含义 |
---|---|
400 | 该状态码表示请求报文中存在语法错误。当错误发生时,需修改请求的内容后再次发送请求 |
401 | 该状态码表示发送的请求需要有通过 HTTP 认证(BASIC 认证、DIGEST 认证)的认证信息 |
403 | 该状态码表明对请求资源的访问被服务器拒绝了 |
404 | 该状态码表明服务器上无法找到请求的资源 |
以 5xx
为开头的响应标头都表示服务器本身发生错误
状态码 | 含义 |
---|---|
500 | 该状态码表明服务器端在执行请求时发生了错误 |
503 | 该状态码表明服务器暂时处于超负载或正在进行停机维护,现在无法处理请求 |
响应头
HTTP响应中的常用响应头(消息头)
Location | 服务器通过这个头,来告诉浏览器跳到哪里 |
Server | 服务器通过这个头,告诉浏览器服务器的型号 |
Content-Encoding | 服务器通过这个头,告诉浏览器,数据的压缩格式 |
Content-Length | 服务器通过这个头,告诉浏览器回送数据的长度 |
Content-Language | 服务器通过这个头,告诉浏览器语言环境 |
Content-Type | 服务器通过这个头,告诉浏览器回送数据的类型 |
Refresh | 服务器通过这个头,告诉浏览器定时刷新 |
Content-Disposition | 服务器通过这个头,告诉浏览器以下载方式打数据 |
Transfer-Encoding | 服务器通过这个头,告诉浏览器数据是以分块方式回送的 |
Expires | 控制浏览器不要缓存 |
Cache-Control | no-cache |
Pragma | no-cache |
设置Location响应头,实现请求重定向
package gacl.http.study;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author gacl
*
*/
public class ServletDemo01 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setStatus(302);//设置服务器的响应状态码
/**
*设置响应头,服务器通过 Location这个头,来告诉浏览器跳到哪里,这就是所谓的请求重定向
*/
response.setHeader("Location", "/JavaWeb_HttpProtocol_Study_20140528/1.jsp");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
当在浏览器中使用URL地址"http://localhost:8080/JavaWeb_HttpProtocol_Study_20140528/servlet/ServletDemo01"访问ServletDemo01时,就可以看到服务器作出响应后发送到浏览器的状态码和响应头信息,如下图所示
服务器返回一个302状态码告诉浏览器,你要的资源我没有,但是我通过Location响应头告诉你哪里有,而浏览器解析响应头Location后知道要跳转到/JavaWeb_HttpProtocol_Study_20140528/1.jsp页面,所以就会自动跳转到1.jsp
设置content-disposition响应头,让浏览器下载文件
package gacl.http.study;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ServletDemo05 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/**
* 设置content-disposition响应头,让浏览器下载文件
*/
response.setHeader("content-disposition", "attachment;filename=xxx.jpg");
InputStream in = this.getServletContext().getResourceAsStream("/img/1.jpg");
byte buffer[] = new byte[1024];
int len = 0;
OutputStream out = response.getOutputStream();
while ((len = in.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}