上面的页面相信大家都很熟悉,我们在上网时,通常是以浏览器作为进入互联网的入口,在地址栏输入指定的网址或者在搜索引擎输入指定的字符串,浏览器就会跳转到特定的网页,将其展示出来。这其中的原理是什么呢?
实际上我们输入URL后,我们的浏览器根据HTTP协议,向Web服务器发送了一个请求, Web服务器接到请求后进行处理,生成相应的响应,然后发送给浏览器,浏览器解析响应中的数据,然后将其展示在浏览器页面。通过上面的一系列操作,就完成了一次完整的HTTP请求过程。
什么是HTTP协议
协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或规则,超文本传输协议(HTTP)是一种是一个基于请求与响应,无状态的,应用层的协议,基于TCP/IP协议传输数据的通信协议,它允许将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览器。
请求与响应:客户端发送请求,服务器端响应数据。
无状态的:协议对于事务处理没有记忆能力,客户端第一次与服务器建立连接发送请求时需要进行一系列的安全认证匹配等,因此增加页面等待时间,当客户端向服务器端发送请求,服务器端响应完毕后,两者断开连接,也不保存连接状态。下一次客户端向同样的服务器发送请求时,由于他们之前已经遗忘了彼此,所以需要重新建立连接。
应用层:Http是属于应用层的协议,配合TCP/IP使用。
TCP/IP:Http使用TCP作为它的支撑运输协议。HTTP客户机发起一个与服务器的TCP连接,一旦连接建立,浏览器(客户机)和服务器进程就可以通过套接字接口访问TCP。
一次完整的HTTP请求过程
当我们在web浏览器的地址栏中输入:www.google.com,然后回车,到底发生了什么?
-
对www.google.com这个网址进行DNS域名解析,得到对应的IP地址;
-
根据这个IP地址,找到对应的服务器,发起TCP的三次握手;
-
建立TCP连接后发起HTTP请求;
-
服务器收到HTTP请求后,进行相应的处理,然后向浏览器发送HTTP响应;
-
浏览器从HTTP响应中解析html代码,对页面进行渲染呈现给用户。
这里我们主要对请求(request)和响应(response)进行学习,以 tomcat 服务器为例,当浏览器请求服务器时,tomcat 会把请求消息封装成 request 对象,把响应信息封装成 response 对象。
HTTP请求(request)
浏览器向服务器请求某个 web 资源时,称之为浏览器向服务器发送了一个 http 请求。一个完整 http 请求消息结构应该包含四个部分:
- 请求行 :
GET :称之为请求方式,表示了我们数据提交的方式,除了 GET 还包括POST、DELETE、HEAD、OPTIONS、PUT、TRACE。其中 GET 和 POST 是最常见的 HTTP 方法。
一般来说,当我们点击超链接,通过地址栏访问都是 GET 请求方式。通过表单提交的数据一般是 POST方式。可以简单理解 GET 方式用来查询数据,POST 方式用来提交数据,GET 的提交速度比 POST 快。
GET方式:在URL地址后附带的参数是有限制的,其数据容量和浏览器有关,不同的浏览器其数据容量可能不同。 POST 方式:可以在请求的实体内容中向服务器发送数据,理论上传送的数据量无限制。
/WEB12/form.html:代表的是 URL 地址,它和报文头的 Host 属性组成完整的请求 URL 地址,
HTTP/1.1:代表当前的协议名称及版本号。 - 请求头 :
请求头是浏览器自动封装的,包含若干个属性,服务端据此获取客户端的信息,其格式为键值对:属性名:属性值。如:
Host: local host:8080 → 告知服务器,浏览器准备访问的主机的地址和端口号
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1) →告知服务器,当前浏览器的详细信息
Referer: localhost:8080 → 告知服务器,客户端是从那个页面来的—反盗链
cookie: xxxx=xxxxxxxx → 将浏览器的 cookie 发送到服务器进行判断 - 请求空行 : 用来分割请求头和请求体的;
- 请求体 :
请求体将一个页面表单中的组件值通过 param1=value1¶m2=value2 的键值对形式编码成一个格式化串,它承载多个请求参数的数据。这里表单的提交方式必须是 POST 方式,请求体中才会有内容,如果采用 GET 方式,浏览器会将表单数组以键值对的形式拼接在地址栏的 URL 地址末端,此时请求体的内容即为空。
WEB 服务器将请求按照上面的结构进行封装后,还提供了很多操作方法,方便我们来获取和设置 request 对象中的数据,下面就介绍一些比较常用的方法。
方法 | 功能 |
---|---|
String getQueryString() | 以键值对的形式返回url地址栏的参数值,如key1=value1&key2=value2; |
String getHeader(String name) | 通过请求头的名称获取请求头的值 |
Enumeration getHeaderNames() | 获取所有的请求头名称 |
String getParameter(String name) | 根据参数名称获取参数值 |
String[] getParameterValues(String name) | 根据参数名称获取参数值的数组 |
Enumeration getParameterNames() | 获取所有请求的参数名称 |
Map<String,String[]> getParameterMap() | 获取所有参数的map集合 |
注:对于 getQueryString() 方法,如果地址栏的 url 中包含了中文,该中文会被编码为特定格式;
在执行获取表单参数的方式时(即%Parameter%方法),需提前设置 request 的字符编码集,request.setCharacterEncoding(“utf-8”),否则返回的对象中会出现乱码,
另外 request 也是域对象之一,在一定范围内可以共享数据,request 域的作用范围为一次请求的范围,一般用于请求转发的多个资源之间共享数据。web 服务器为域对象提供了三个特有的方法。
- void setAttribute(String name,Object obj):存储数据
- Object getAttitude(String name):通过键获取值
- void removeAttribute(String name):通过键移除键值对
通过以上三个方法,多个资源可以在同一个 request 域中对域中数据进行增删改查。
HTTP响应(response)
WEB 服务器在接收到浏览器的消息后,将需要响应的消息封装在 response 对象中,该对象的结构和 request 对象相似,也由四个部分构成,只是其中的内容有所不同。
- 响应行:
HTTP/1.1:代表当前的协议名称及版本号。
200 : 状态码,代表服务器对请求的反应,告诉客户端发生了什么事。
OK : 状态消息,解释状态码的简单短语,放便理解 - 响应头
响应头是服务器自动封装的,包含若干个属性,其格式为键值对:属性名:属性值。
content-type: text/html; charset=UTF-8 → 通知浏览器,响应体中的html代码的编码格式
content-encoding: gzip → 通知服务端选定的编码信息浏览器在拿到响应正文
后,依据 Content-Encoding 进行解压。
set-cookie:xxx=xxxxxxxx → 向浏览器发送一个 cookie 信息 - 响应空行 :用来分隔响应头和响应体的内容
- 响应体
根据浏览器的请求,将对应的html代码或其他资源封装在响应体中。
上面响应行中的状态代码由三位数字组成,第一个数字定义了响应的类别,且有五种可能取值。
- 1xx:指示信息–表示请求已接收,继续处理。
- 2xx:成功–表示请求已被成功接收、理解、接受。
- 3xx:重定向–要完成请求必须进行更进一步的操作。
- 4xx:客户端错误–请求有语法错误或请求无法实现。
- 5xx:服务器端错误–服务器未能实现合法的请求。
和 request 对象相比,操作 response 的方法相对较少,主要包括如下方法:
方法 | 功能 |
---|---|
setStatus(int sc) | 设置状态码 |
setHeader(String name, String value) | 设置响应头 |
PrintWriter getWriter() | 从response中获取字符输出流 |
ServletOutputStream getOutputStream() | 从response中获取字节输出流 |
void sendRedirect(String var1) | 重定向到指定的url |
注:通过字符输出流向页面输出中文字符时,应该调用 response.setContextType(“utf-8”) 来设置字符集编码,避免服务器和浏览器的字符编码集不一致导致的乱码
转发和重定向
在 JavaWeb 中,实现页面的跳转有两种方式,分别由 request 和 response 实现,即转发和重定向。
- 转发方法 :
request.getRequestDispatcher("xxxx").forward(request, response);
;
request对象通过getRequestDispathcer()获取一个转发对象,然后调forward()方法进行转发,该方法只能将请求转发给同一个WEB应用中的组件,转发过程中浏览器地址栏保持初始的URL地址不变。
转发是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器,浏览器根本不知道服务器发送的内容是从哪儿来的,所以它的地址栏中还是原来的地址。
- 重定向方法:
response.sendRedirect("xxxxx");
。
response对象调用sendRedirect()实现页面的重定向。它不仅可以重定向到当前应用程序中的其他资源,还可以重定向到同一个站点上的其他应用程序中的资源,甚至是使用绝对URL重定向到其他站点的资源。
服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,一般来说浏览器会用刚才请求的所有参数重新请求,所以session,request参数都可以获取。
所以,前者更加高效,在前者可以满足需要时,尽量使用forward()方法,并且,这样也有助于隐藏实际的链接。