Response
今日目标
0. http响应
1. response【重点】
2. ServletContext:应用上下文对象
3. 综合案例
零 Http响应
之前我们已经学习过Http请求, 现在我们一起再来学习Http响应
0.1 浏览器查看Http响应协议
0.2 HTTP响应消息格式
① 响应行
* 格式
协议/版本号 状态码
* 例如
HTTP/1.1 200
* 常见状态码
--------------- 用户可以正常访问页面
200 :表示成功
302 :重定向(response学习)
304 :从缓存中读取数据
(如果这个资源没有变化,浏览器是会缓存的,下次请求,就直接从缓存中读取,提高效率)
--------------- 用户无法正常访问页面
404:请求资源未找到(not found)
405:请求的方法未找到(明天讲了servlet给大家演示....)
500:服务器内部错误(java代码写错了.....)
② 响应头
* 格式
响应头名称:响应头的值
* 例如
Last-Modified: Mon, 13 Apr 2020 06:11:24 GMT
常见响应头:
1. Location:通常与状态码302一起使用,实现重定向操作
Location:http://www.itcast.cn
2. Content-Type:服务器告诉客户端,返回响应体的数据类型和编码方式
Content-Type:text/html;charset=utf-8
3. Content-Disposition:服务器告诉客户端,以什么样方式打开响应体
* in-line(默认):浏览器直接打开相应内容,展示给用户
* attachment;filename=文件名:浏览器以附件的方式保存文件 【文件下载】
4. Refresh:在指定间隔时间后,跳转到某个页面
Refresh:5;http://www.itcast.cn
③ 响应体(正文)
* 服务器返回的数据,由浏览器解析后展示给用户
用户看到页面所有的内容,都是在响应体中返回的
一 Response【重点】
1.1 概述
- response对象表示web服务器给浏览器返回的响应信息
response是由tomcat创建的
- 作用:开发人员可以使用response对象的方法,设置要返回给浏览器的响应信息
注意: tomcat + servlet (服务端)
在response中但凡不是Servlet设置的信息,就是tomcat设置的, 我们可以用Servlet中设置覆盖tomcat的设置
ServletResponse 接口 (理论上兼容大部分协议)
|
HttpServletResponse 接口 (专门指的是http协议的响应)
|
org.apache.catalina.connector.ResponseFacade 实现类(由tomcat提供的)
HTTP响应报文
1.2 设置Http响应行
* 格式
协议/版本号 状态码(status code)
* 例如
HTTP/1.1 200
* API
1. 设置状态码(status code)
void setStatus(int sc)
2. 常见响应状态码:
200:请求和响应都OK(顺利)
302:重定向 (待会)
304:浏览器从缓存中加载数据
404:请求的路径错误或请求的资源不存在(自己开发的时候,路径有问题)
405: 在HttpServlet的子类中, doGet或doPost方法没有重写
500:服务器内部异常
3. 注意事项:上述常见的响应状态码,通常是由tomcat服务器自动响应给浏览器。我们一般是不需要手动设置的;
浏览器缓存(304)
package com.itheima02.response;
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;
/*
servlet开发者可以通过response给浏览器发送数据
(响应)
1. 响应行
1). 协议 (tomcat支持http协议)
2). 状态码 (status code)
I. 200 响应成功
II. 302 重定向
III. 304 读取浏览器缓存
IV. 404 not found 资源不存在
V. 500 服务器错误 (大家可以在tomcat localhost log查看完整的错误信息)
一般情况, 状态码我们不需要在servlet中设置,因为tomcat会根据当前状态进行设置
目前只有一种情况,需要设置(重定向)
response.setStatus(302);
2. 响应头
3. 响应体
# response操作
1. tomcat有默认设置
2. servlet可以手动设置(会覆盖默认设置)
*/
@WebServlet("/MyHttpServlet2")
public class MyHttpServlet2 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// int i = 1/0;
response.setStatus(302);
response.getWriter().print("hello");
}
}
1.3 设置Http响应头
* 格式
响应头名称:响应头的值
(name : value)
* 例如
Content-Length : 5 (指的是响应体内容长度5个字符)
* API
1. 设置指定头名称和对应的值
void setHeader(String name, String value)
2. value值可以由多个参数组成,不同参数之间使用分号隔开:
response.setHeader(key,"value1;value2");
3. 常用响应头:
refresh:定时刷新;
content-type:设置响应数据的数据类型和编码格式; (内容类型)
location:配合302响应状态码完成重定向;(位置)
1.4 设置Http响应体
响应体中包含 响应数据的正文
响应是服务器给浏览器发送数据: 输出流
* API(输出流对象)
1. 字符输出流 : 用于向浏览器输出字符数据(文本)
PrintWriter getWriter()
2. 字节输出流 : 用于向浏览器输出二进制数据(比如文件下载)
ServletOutputStream getOutputStream()
注意:在同一个servlet中,二种类型的输出流不能同时存在,互斥
package com.itheima02.response;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/*
servlet开发者可以通过response给浏览器发送数据
(响应)
1. 响应行
2. 响应头
3. 响应体
0). 服务器发送给浏览器的核心数据
1). 字节输出流 : 操作一切数据
2). 字符输出流 : 操作文本数据
response.getOutputStream();
response.getWriter();
注意: 两个流不能同时使用
# response操作
1. tomcat有默认设置
2. servlet可以手动设置(会覆盖默认设置)
*/
@WebServlet("/MyHttpServlet2")
public class MyHttpServlet2 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// int i = 1/0;
//设置状态码
// response.setStatus(302);
// response.getWriter().print("hello");
//获取响应体字节输出流
ServletOutputStream os = response.getOutputStream();
os.print("hello world");
//获取响应字符输出流
PrintWriter writer = response.getWriter();
writer.print("hello world2");
}
}
二. 响应头的功能【重点】
2.1 响应定时刷新(refresh)
需求
在当前页面停留3秒钟之后,跳转到传智播客首页
步骤分析
1. 通过response设置响应头 Refresh
response.setHeader("Refresh","间隔时间(秒);跳转页面");
package com.itheima02.response;
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.FileInputStream;
import java.io.IOException;
/*
响应头: (name : value)
1. refresh
2. content-type
3. location
4. content-disposition
# 第一个响应头 : refresh(刷新)
response.setHeader(响应头name值, "value值1;value值2" );
response.setHeader("refresh", "5;http://www.baidu.com");
服务器告诉浏览器, 你5秒之后跳转到http://www.baidu.com 刷新页面
*/
@WebServlet("/MyHttpServlet3")
public class MyHttpServlet3 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setHeader("refresh", "5;http://www.baidu.com");
response.setContentType("text/html;charset=utf-8");
response.getWriter().print("<h1>付款成功,5秒之后跳转到首页</h1>");
}
}
2.2 响应体中文乱码(content-type)
需求
向页面输出中文数据没有乱码
原因分析
1. 通过response获取字符输出流
PrintWriter pw = response.getWriter();
2. 通过字符输出输出中文字符
pw.write("中文....");
3. 浏览器访问,网页出现中文乱码
4. 解决 : 统一浏览器和服务器编码(utf-8)
response.setContentType("text/html;charset=utf-8");
解决中文乱码
package com.itheima02.response;
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.FileInputStream;
import java.io.IOException;
/*
响应头: (name : value)
1. refresh
2. content-type
3. location
4. content-disposition
# 第二个响应头 : content-type (内容类型)
服务器告诉浏览器,使用何种语法解析响应体,使用何种字符集解码响应体
response.setHeader("content-type", "text/html;charset=utf-8");
1). 响应体中文乱码
I. 编码 : servlet (utf-8)
II. 解码 : 浏览器
服务器告诉浏览器, 用utf-8解码响应体
2). MIME type (多用途互联网邮件扩展MIME,Multipurpose Internet Mail Extensions)
windows后缀名 : txt html json
MIME type : text/plain text/html application/json
windows : \
java : / (unix系统)
服务器告诉浏览器, 用text/html的语法解析响应体
*/
@WebServlet("/MyHttpServlet3")
public class MyHttpServlet3 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// response.setHeader("content-type", "text/plain;charset=utf-8");
response.setContentType("text/html;charset=utf-8"); //是上面的简化写法
response.getWriter().print("<h1>付款成功,5秒之后跳转到首页</h1>");
}
}
2.3 响应重定向(location+302)
需求
用户访问CServlet后,服务器告诉浏览器重定向到DServlet
步骤分析
* 方式一
// 1.设置状态码
response.setStatus(302);
// 2.设置响应头 Location
response.setHeader("Location","重定向网络地址");
* 方式二
// 1.response这哥们封装专门处理重定向的方法 (掌握)
response.sendRedirect("重定向网络地址");
重定向特点
# 重定向是浏览器行为
1. 起码发起两次请求
2. 浏览器地址栏的url被修改了(指向最后访问的地址)
3. 可以访问服务器外部资源
4. 不能通过request域对象共享数据
<a href="CServlet?msg=生煎">重定向</a> <br>
package com.itheima03.redirect;
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("/CServlet")
public class CServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 接收请求
String msg = request.getParameter("msg");
System.out.println("CServlet:" + msg);
//2. 业务处理
System.out.println("CServlet: 收钱");
//3. 响应(重定向)
// response.setStatus(302);
// response.setHeader("location", "DServlet");
//等价于上面两行
response.sendRedirect("DServlet");
}
}
package com.itheima03.redirect;
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("/DServlet")
public class DServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 接收请求
//2. 业务处理
System.out.println("DServlet:煎包子");
//3. 响应
response.setContentType("text/html;charset=utf-8");
response.getWriter().print("给你两个生煎");
}
}
请求转发与重定向的区别
从最终效果来看,请求转发和重定向非常相似
1. 哪个对象的方法
1). 请求转发 : request
request.getRequestDispatcher(转发地址).forward(request,response)
2). 重定向 : response
response.sendRedirect(重定向地址); // 302状态码 + location头
2. 行为人
请求转发 : 服务器内部行为,浏览器不知道服务器内部发生了什么
重定向 : 浏览器行为
可以定向到其他服务器,但是请求转发只能在本服务器内
3. 请求次数
请求转发 : 1次
重定向: 起码2次
浏览器会限制重定向的次数,比如 google浏览器不超过20次
4. 数据共享 (重要)
请求转发: request域对象可以传递数据
重定向 : 不可以用request域对象传递数据
重定向涉及多次请求, 超出一个request作用范围
5. 地址栏指向
请求转发: 一开始设置的路径 AServlet
一次请求
重定向: 最终指向最后一次请求的地址 DServlet
多次请求,后续请求地址覆盖前面请求地址
6. 总结
请求转发: 就一次请求, 可以使用request域传递数据,不可以转发到其他服务器
重定向: 涉及多次请求,不可以用request域传递数据,但是可以定向到其他的服务器
7. 使用
a. 如果用request域对象传递数据,并且两个资源在同服务器内 -> 请求转发
b. 如果不需要request传递数据,或两个资源在不同服务器上 -> 重定向