今日内容
1. HTTP协议:响应消息
2. Response对象
3. ServletContext对象
1、HTTP协议
HTTP协议可以分为2部分描述:请求消息与响应消息。
请求消息:客户端发送给服务器端的数据
* 数据格式:
1. 请求行
2. 请求头
3. 请求空行
4. 请求体
响应消息:服务器端发送给客户端的数据
* 数据格式:
1. 响应行
1) 组成:协议/版本 响应状态码 状态码描述
eg:200 ok:告诉客户端响应状态码200代表OK,响应成功
2) 响应状态码:服务器告诉客户端浏览器本次请求和响应的一个状态。
1. 状态码都是3位数字
2. 分类:
1. 1xx:服务器接收客户端消息,但没有接受完成,等待一段时间后,发送1xx多状态码
2. 2xx:成功。代表:200
3. 3xx:重定向(视频5.15解析),重定向也是资源跳转的一种方式,与Request的请求转发很类似。注意区分请求转发与重定向。
代表:302(重定向),304(访问缓存):访问缓存就是提示客户端浏览器,它访问的信息之前访问过,缓存在客户端本地,且服务器没有更改资源,可以去客户端本地找。
4. 4xx:客户端错误。
* 代表:
* 404(请求路径没有对应的资源)
* 405:请求方式没有对应的doXxx方法。比如我们使用XXX方法向某一个Servlet类请求资源,但是这个类没有处理XXX请求的方法doXXX,就会出现405(演示405错误:视频3-12.00解析)
5. 5xx:服务器端错误。代表:500(服务器内部出现异常),出现这种情况一般是我们服务器的代码写错。
2. 响应头:
1. 格式:头名称: 值
2. 常见的响应头:
1. Content-Type:服务器告诉客户端本次响应体数据格式以及编码格式。(以后遇到浏览器显示中文乱码,需要在服务器端代码中的Response响应设置Content-Type(或者使用setContentType()方法)解决;而服务器读取浏览器的请求信息出现中文乱码,也需要在浏览器端使用 setCharacterEncoding(编码方式) 来设置。)
浏览器会根据服务器告知的编码方式去解析响应消息。
2. Content-disposition:服务器告诉客户端以什么格式打开响应体数据
* 值:
* in-line:默认值,在当前页面内打开
* attachment:以附件形式打开响应体。 比如我们点击一个超链接,它不会在浏览器里面打开这个超链接,而是弹出一个框框,让你去下载。
*格式是:attachment;filename=xxx:以附件形式打开响应体。文件下载。
3. 响应空行
4. 响应体:传输的数据
响应消息举例:我们在火狐浏览器打开一个百度界面-F12-网络-刷新,找到“https://www.baidu.com”资源,打开,找到消息头的原始头,这些就是响应消息。响应体可以在响应处找到。
HTTP/1.1 200 OK (响应行)
Bdpagetype: 1 (响应头)
Bdqid: 0xd5f9a0b9000c99ac
Cache-Control: private
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/html
Cxy_all: monline_3_dg+9f09c7fb838c1316f0a42904cbaa1e40
Date: Fri, 07 Feb 2020 13:12:43 GMT
Expires: Fri, 07 Feb 2020 13:12:43 GMT
P3p: CP=" OTI DSP COR IVA OUR IND COM "
Server: BWS/1.1
Set-Cookie: BDRCVFR[Fc9oatPmwxn]=aeXf-1x8UdYcs; path=/; domain=.baidu.com
Set-Cookie: delPer=0; path=/; domain=.baidu.com
Set-Cookie: BDSVRTM=10; path=/
Set-Cookie: BD_HOME=0; path=/
Set-Cookie: H_PS_PSSID=1465_21108; path=/; domain=.baidu.com
Strict-Transport-Security: max-age=172800
Traceid: 1581081163028858420215418531515709823404
Vary: Accept-Encoding
X-Ua-Compatible: IE=Edge,chrome=1
Transfer-Encoding: chunked
(响应空行)
百度响应回去的就是我们百度的界面内容。(响应体)
当然,我们也可以启动自己的服务器,在默认访问界面index.jsp的body下加一句
<body>
hello response
</body>
然后将当前项目的虚拟目录改为:/ResponsePro ,启动当前服务器,访问index.jsp,同样使用火狐浏览器,就可以看到响应的消息:
HTTP/1.1 200 (响应行)
Set-Cookie: JSESSIONID=3E2AA6B18DE8FD18B05C0BE5C9F3EE67; Path=/ResponsePro; HttpOnly (响应头:用来设置响应消息的展示)
Content-Type: text/html;charset=UTF-8
Content-Length: 100
Date: Fri, 07 Feb 2020 13:30:02 GMT
(响应空行)
<html> (响应体)
<head>
<title>$Title$</title>
</head>
<body>
hello response
</body>
</html>
405响应状态码演示:先创建ServletTest类(删除doGet方法),访问:http://localhost:8080/ResponsePro/servletTest,出现405错误。因为我们使用GET方式提交请求,但是ServletTest类没有这种请求的处理doGet方法,所以出现405错误。
package lkjtest.web.servlet;
@WebServlet("/servletTest")
public class ServletTest extends HttpServlet
{
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
}
}
2、Response对象
功能:设置响应消息。
1. 设置响应行
1) 格式:HTTP/1.1 200 ok
2) 设置状态码:setStatus(int sc)
2. 设置响应头:setHeader(String name, String value)
3. 设置响应体:设置响应体,应该使用输出流Writer或者OutputStream,将我们想设置的内容写出到响应消息中。
* 使用步骤:
1) 获取输出流
* 字符输出流:PrintWriter getWriter()
* 字节输出流:ServletOutputStream getOutputStream() (同样将ServletOutputStream当中OutputStream使用就可以)
2) 使用输出流,将数据输出到客户端浏览器
Response对象使用案例
1. 完成重定向
重定向:资源跳转的方式。请求转发也是资源跳转的一种方式。(重定向详解:视频6-1.25)
如下图,重定向过程中,A资源告诉浏览器的2件事
1.告诉浏览器重定向:状态码302
2.告诉浏览器资源的路径:响应头location:B资源的路径
一般我们使用sendRedirect()方法来实现重定向
下面对请求转发与重定向进行区分(重要):一般会问:forward 和 redirect 区别。
* 重定向的特点:redirect
1.浏览器地址栏路径发生变化
2. 重定向可以访问其他站点(服务器)的资源
3. 重定向是两次请求。不能使用request对象来共享数据,因为此时有多次请求,就有多个Request对象。
* 请求转发的特点:forward
1. 浏览器地址栏路径不发生变化
2. 只能转发到当前服务器内部资源中。
3. 转发是一次请求,既多个被访问的Servlet资源之间只有一次请求。可以使用request对象在request域内进行资源的共享。
重定向相关代码
//ResponseTest1类
package lkjtest.web.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/responseTest1")
public class ResponseTest1 extends HttpServlet
{
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
System.out.println("responseTest1 run....111111");
//这里注意对比与Request对象请求转发的区别
/*
//访问/responseTest1,会自动跳转到/responseTest2资源
response.setStatus(302);//1、设置响应状态码为302:重定向
//这里注意设置重定向的路径时加上虚拟目录,包含虚拟目录和类的资源路径。我们设置Deployment的时候将虚拟目录设置为“/ResponsePro”
//如果虚拟目录设置为“/”,那么这里location的地址就设置为资源路径就可以“/responseTest2”
response.setHeader("location" , "/ResponsePro/responseTest2");//2、设置location响应头信息。告诉浏览器重定向的资源的地址
*/
//我们发现重定向其实只需要设置重定向下一个资源的路径即可,可以使用sendRedirect这个方法来实现重定向,比较方便
//sendRedirect(要转发的路径,既虚拟目录 + 跳转的资源路径)
//动态获取虚拟目录(虚拟目录写死不好,一当我们将虚拟目录修改,就需要修改全部使用到虚拟目录的地方,十分麻烦。我们一般都会动态获取虚拟目录)
// String contextPath = request.getContextPath();//通过Request对象来获取(当前项目)虚拟目录,因为重定向也是在同一个项目下,当前类与要转发到类的虚拟目录相同
// response.sendRedirect(contextPath + "/responseTest2");//以后重定向使用sendRedirect
//重定向可以访问其他站点的资源
// response.sendRedirect("http://www.itcast.cn");//会跳转到其他站点的资源下。
//重定向不能使用Request共享数据
request.setAttribute("msg" , "redirect");
response.sendRedirect("/ResponsePro/responseTest2");//通过redirect共享数据失败
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
this.doPost(request , response);
}
}
//-------------------------------------------------------
//ResponseTest2
package lkjtest.web.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/responseTest2")
public class ResponseTest2 extends HttpServlet
{
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
System.out.println("responseTest2 run...22222222");//访问/responseTest1,如果重定向成功,会打印这一句
//演示重定向不能使用Request共享数据
Object msg = request.getAttribute("msg");
System.out.println(msg);//不能打印出msg,打印null
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
this.doPost(request , response);
}
}
- 补充:Response之相对路径和绝对路径(重要)
我们在重定向或者请求转发的时候需要填写路径,相应的写法如下:(这部分见视频8、9的解析)
路径分类如下:
1. 相对路径:通过相对路径不可以确定唯一资源
* 如:./index.html (代表当前目录下的index.html资源,这样我们就必须找到当前路径)
* 不以/开头,以.开头路径
* 规则:找到当前资源和目标资源之间的相对位置关系(见视频7-4.15,这部分直接看视频即可,太繁琐不再记录)
* ./:当前目录
* ../:后退一级目录
2. 绝对路径:通过绝对路径可以确定唯一资源
* 如:http://localhost/day15/responseDemo2(完整的绝对路径)
/day15/responseDemo2(省略了协议、服务器的IP或域名、端口号)
* 以/开头的路径
* 规则:判断定义的路径是给谁用的?
* 给客户端浏览器使用:需要加虚拟目录(项目的访问路径)
* 建议虚拟目录动态获取:request.getContextPath()
* <a> , <form> 重定向...都是给客户端使用的
* 给服务器使用:不需要加虚拟目录
* 请求转发路径(目前只有这一个是给服务器端使用的)
1、如何判断路径是给客户端用的还是给服务器用的?
判断请求将来从哪儿发出(视频9-1.25)
请求从浏览器发出,比如在浏览器点击超链接访问服务器,在浏览器通过地址栏输入路径直接访问服务器,都必须加虚拟路径。我们的重定向的2次请求都是从浏览器发出的。
请求从服务端发出,比如前面说的请求转发,请求是从服务器内的一个Servlet类转发到另一个Servlet类,这就是在服务器内使用,不加虚拟目录。
2、为什么给客户端使用要加虚拟目录,而给服务器端使用不需要加虚拟目录(视频9-5.45)
相对路径解析的相关代码(结合视频)
我们在web目录下放location.html,通过location.html访问当前项目下的ResponseTest2类
<!--location.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>找到当前资源和目标资源之间的相对位置关系</h1>
<!--下面讨论的是相对路径
需要注意,只有项目的名称(虚拟目录)才算一级资源目录,而像src、web这种文件夹是不算一级资源目录的(重要,需要格外注意)
比如我们在访问location.html的时候,路径是http://localhost:8080/ResponsePro/location.html,只有虚拟目录ResponsePro算一级目录
-->
<P>
当前资源:location.html