ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
[TOC] # 设置响应行 设置响应行的状态码 ~~~ setStatus(int sc) ~~~ # 设置响应头 ~~~ addHeader(String name, String value) addIntHeader(String name, int value) addDateHeader(String name, long date) setHeader(String name, String value) setDateHeader(String name, long date) setIntHeader(String name, int value) ~~~ 其中,add表示添加,而set表示设置 # 设置响应体 ## 响应体设置文本 ~~~ PrintWriter getWriter() ~~~ 获得字符流,通过字符流的write(String s)方法可以将字符串设置到response 缓冲区中,随后Tomcat会将response缓冲区中的内容组装成Http响应返回给浏览器端。 关于设置中文的乱码问题 原因:response缓冲区的默认编码是iso8859-1,此码表中没有中文,可以通过 response的 设置response的编码 ~~~ setCharacterEncoding(String charset) ~~~ 但我们发现客户端还是不能正常显示文字 原因:我们将response缓冲区的编码设置成UTF-8,但浏览器的默认编码是本地系 统的编码,因为我们都是中文系统,所以客户端浏览器的默认编码是GBK,我们可以 手动修改浏览器的编码是UTF-8。 我们还可以在代码中指定浏览器解析页面的编码方式, 通过response的setContentType(String type)方法指定页面解析时的编码是UTF-8 ~~~ response.setContentType("text/html;charset=UTF-8"); ~~~ 上面的代码不仅可以指定浏览器解析页面时的编码,同时也内含 setCharacterEncoding的功能,所以在实际开发中只要编写 response.setContentType("text/html;charset=UTF-8");就可以解决页面输出中文乱码问题。 ## 响应头设置字节 ~~~ ServletOutputStream getOutputStream() ~~~ 获得字节流,通过该字节流的`write(byte[] bytes)`可以向response缓冲区中写入字节,在由Tomcat服务器将字节内容组成Http响应返回给浏览器 ## 设置缓存 设置http响应头控制浏览器禁止缓存当前文档内容 ~~~ response.setDateHeader("expries", -1); response.setHeader("Cache-Control", "no-cache"); response.setHeader("Pragma", "no-cache"); ~~~ 设置http响应头控制浏览器缓存当前文档内容 例,设置http响应头——expires,控制浏览器缓存当前网页内容一个小时 ~~~ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setDateHeader("expires", System.currentTimeMillis()+1000*3600); String data = "aaaaaaaaaaaaaaa"; response.getWriter().write(data); } ~~~ ## 定时刷新网页 控制浏览器定时刷新网页 ~~~ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setHeader("refresh", "3"); // 设置refresh响应头控制浏览器每隔3秒钟刷新一次 String data = new Random().nextInt(1000000) + ""; response.getWriter().write(data); } ~~~ 3秒后刷新到首页(index.jsp) ~~~ // 假设程序运行到此,用户登录成功了 response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); response.setHeader("refresh", "3;url='/day06/index.jsp'"); // 3秒后刷新到首页(index.jsp) response.getWriter().write("恭喜你,登录成功,本浏览器将在3秒后跳转到首页,如果没有跳,请点<a href=''>超链接</a>"); ~~~ # 示例 ## 向页面输出一个片段 ~~~ //获取流 PrintWriter writer = response.getWriter(); //通过流写html writer.write("<h1>11</h1>"); writer.write("222"); ~~~ ## 重定向 302 ~~~ //重定向 参数:重定向的地址 response.sendRedirect("1.html"); ~~~ ![](https://box.kancloud.cn/1fbc569df14bb31476207d8972b65d6f_1894x612.png) 相对路径在转发时可能会失效 重定向写绝对路径的时候需要带项目名,由客户端执行 由服务器执行解析的地址,默认在前面加localhost:8080/项目名 转发由服务器执行,不需要添加项目名 ## 设置响应头 ~~~ response.setHeader("Content-Type", "text/html;charset=utf-8"); ~~~ # base标签 base标签可以让我们把相对路径当做绝对路径来使用 base标签定义前缀url和页面中的相对地址进行拼接 会把base标签中的url和a标签中的url拼接 在html中的头部写 ~~~ <base href="http://localhost:8080/Test/" /> ~~~ 不过一般base中的url是动态获取 ~~~ <base href="http://<%=request.getServerName() %>:<%=request.getServerPort() %><%=request.getContextPath() %>/" /> ~~~ # 文件下载 文件下载的实质就是文件拷贝,将文件从服务器端拷贝到浏览器端。所以文件下载需 要IO技术将服务器端的文件使用InputStream读取到,在使用 ServletOutputStream写到response缓冲区中 ![](https://box.kancloud.cn/b3f031d8c0fe0beec3d39f30ffb502f6_426x208.png) 上述代码可以将图片从服务器端传输到浏览器,但浏览器直接解析图片显示在页面上, 而不是提供下载,我们需要设置两个响应头,告知浏览器文件的类型和文件的打开方 式。 1. 告知浏览器文件的类型:response.setContentType(文件的MIME类型); 2. 告示浏览器文件的打开方式是下载 ~~~ response.setHeader("Content-Disposition","attachment;filename=文件名称"); ~~~ ![](https://box.kancloud.cn/2628b09282e99339438825261607c79d_461x254.png) 但是,如果下载中文文件,页面在下载时会出现中文乱码或不能显示文件名的情况, 原因是不同的浏览器默认对下载文件的编码方式不同,ie是UTF-8编码方式,而火狐 浏览器是Base64编码方式。所里这里需要解决浏览器兼容性问题,解决浏览器兼容 性问题的首要任务是要辨别访问者是ie还是火狐(其他),通过Http请求体中的一 个属性可以辨别 ![](https://box.kancloud.cn/d9395048b9c1014d72319bc734b2d755_448x36.png) 解决乱码方法如下: ~~~ if (agent.contains("MSIE")) { // IE浏览器 filename = URLEncoder.encode(filename, "utf-8"); filename = filename.replace("+", " "); } else if (agent.contains("Firefox")) { // 火狐浏览器 BASE64Encoder base64Encoder = new BASE64Encoder(); filename = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?="; } else { // 其它浏览器 filename = URLEncoder.encode(filename, "utf-8"); } ~~~ 其中agent就是请求头User-Agent的值 ![](https://box.kancloud.cn/034e84b0909c799e777956df8c54528d_475x300.png) ## 实现思路 1. 获取要下载的文件的绝对路径。 2. 获取要下载的文件名。 3. 设置content-disposition响应头控制浏览器以下载的形式打开文件。 4. 获取要下载的文件输入流。 5. 创建数据缓冲区。 6. 通过response对象获取OutputStream流。 7. 将FileInputStream流写入到buffer缓冲区。 8. 使用OutputStream将缓冲区的数据输出到客户端浏览器 使用Response实现中文文件下载。 下载中文文件时,需要注意的地方就是中文文件名要使用URLEncoder.encode方法进行编码`(URLEncoder.encode(fileName, "字符编码"))`,否则会出现文件名乱码 ~~~ public class ResponseDemo3 extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1.获取要下载的文件的绝对路径 String path = this.getServletContext().getRealPath("/download/你好.jpg"); // 2.获取要下载的文件名 String filename = path.substring(path.lastIndexOf("\\")+1); // 3.设置content-disposition响应头控制浏览器以下载的形式打开文件,如果下载文件是中文文件,则文件名需要经过url编码 response.setHeader("content-disposition", "attachment;filename="+URLEncoder.encode(filename, "UTF-8")); InputStream in = null; OutputStream out = null; try { // 4.获取要下载的文件输入流 in = new FileInputStream(path); int len = 0; // 5.创建数据缓冲区 byte[] buffer = new byte[1024]; // 6.通过response对象获取OutputStream流 out = response.getOutputStream(); // 7.将FileInputStream流写入到buffer缓冲区 while((len=in.read(buffer)) != -1) { // 8.使用OutputStream将缓冲区的数据输出到客户端浏览器 out.write(buffer, 0, len); } } finally { if(in != null) { try { in.close(); } catch (Exception e) { e.printStackTrace(); } } if(out != null) { try { out.close(); } catch (Exception e) { e.printStackTrace(); } } } } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } } ~~~ 文件下载注意事项:**编写文件下载功能时推荐使用OutputStream流,避免使用PrintWriter流,因为OutputStream流是字节流,可以处理任意类型的数据,而PrintWriter流是字符流,只能处理字符数据,如果用字符流处理字节数据,会导致数据丢失。** # 细节问题 getOutputStream和getWriter方法分别用于得到输出二进制数据、输出文本数据的ServletOuputStream、Printwriter对象。 getOutputStream和getWriter这两个方法互相排斥,调用了其中的任何一个方法后,就不能再调用另一方法。 例,同时调用getOutputStream()和getWriter()方法会抛: `java.lang.IllegalStateException: getOutputStream() has already been called for this response` ~~~ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getOutputStream(); response.getWriter(); } ~~~ 虽然以上代码你不会愚蠢的写出来,但作为一名合格的JavaWeb开发者一定会碰到这个问题,你碰到的代码可能是这样的 * ResponseDemo8 ~~~ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getOutputStream(); // response.getWriter(); this.getServletContext().getRequestDispatcher("/ResponseDemo9").forward(request, response); } ~~~ * ResponseDemo9 ~~~ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getWriter(); } ~~~ 转发时用到的是同一个request请求,你可能会犯以上这样的错误。 Servlet程序向ServletOutputStream或PrintWriter对象中写入的数据将被Servlet引擎从response里面获取,Servlet引擎将这些数据当作响应消息的正文,然后再与响应状态行和各响应头组合后输出到客户端。 Serlvet的service方法结束后,Servlet引擎将检查getWriter或getOutputStream方法返回的输出流对象是否已经调用过close方法,如果没有,Servlet引擎将调用close方法关闭该输出流对象