板块一 Servlet编程:第四节 HttpServletResponse对象全解与重定向 来自【汤米尼克的JAVAEE全套教程专栏】

news/发布时间2024/5/14 23:32:56

板块一 Servlet编程:第四节 HttpServletResponse对象全解与重定向

  • 一、什么是HttpServletResponse
  • 二、响应数据的常用方法
  • 三、响应乱码问题
      • 字符流乱码
      • 字节流乱码
  • 四、重定向:sendRedirect
      • 请求转发和重定向的区别

在上一节中,我们系统的学习了请求响应在Servlet中service()方法的第一个形参HttpServletRequest(请求)对象,这一节中我们将学习它的兄弟,service()方法的第二个形参HttpServletResponse(响应)对象

一、什么是HttpServletResponse

在我们已然熟悉的浏览器访问Servlet的过程中。Request和Response 对象分别代表请求和响应:通过Request对象获取客户端数据;通过 Response 对象向客户端输出数据:
在这里插入图片描述
service()方法中形参接收的是HttpServletResponse接口的实例化对象,它继承自ServletResponse接口,专门用来封装HTTP响应消息,由于HTTP响应消息分为状态行响应消息头消息体三部分(详见HTTP协议理论与服务器请求响应原理小节),因此在HttpServletResponse中定义了状态行、响应消息头、消息体三部分。

  • 状态行部分
    响应消息头包含了关于响应的附加信息,例如内容类型、内容长度、缓存控制等。由setStatus(int status)方法实现,该方法用于设置HTTP响应消息的状态码,并生成相应代码;默认会生成一个状态码为200的状态行;
  • 响应消息头部分
    响应消息头包含了关于响应的附加信息,例如内容类型、内容长度、缓存控制等。可以使用setHeader(String name, String value)方法设置响应消息头的字段和值,例如setHeader("Content-Type", "text/html")设置内容类型为HTML。如果要设置相同字段的多个值,可以使用addHeader(String name, String value)方法,例如addHeader("Set-Cookie", "cookie1=value1")。此外还可以使用一些特定的方法来设置常见的响应消息头,例如setContentType(String type)setContentLength(int len)
  • 消息体部分
    消息体包含了实际的响应数据。可以通过获取ServletOutputStream或PrintWriter对象来写入响应消息体。getOutputStream()方法返回一个可以写入二进制数据的ServletOutputStream对象。
    getWriter()方法返回一个可以写入字符数据的PrintWriter对象。
    可以使用这些对象的方法将数据写入响应消息体,例如print(String s)、write(byte[] b)等。

二、响应数据的常用方法

接收到客户端请求后,可以通过HttpServletResponse对象直接进行响应,响应时需要获取输出流。
有两种形式:

  • getWriter() 获取字符流(只能响应字符串)
  • getOutputStream() 获取字节流(能响应一切数据)

响应回的数据到客户端被浏览器解析
注意:两者不能同时使用

实例
在start.java导入PrintWriter类,并在service()中写入测试代码

// 获取字符输出流
PrintWriter writer = resp.getWriter();
//输出数据
writer.write("Hello");

启动服务器,在浏览器中访问得
在这里插入图片描述
在start.java中导入ServletOutputStream类,并在service()中写入测试代码

//得到字节输出流
ServletOutputStream out = resp.getOutputStream();
// 输出数据
out.write("Hi".getBytes());

启动服务器,在浏览器中访问得
在这里插入图片描述
但当两者同时使用时
start.java

package www.caijiyuan;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;@WebServlet("/start")
public class start extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 获取字符输出流PrintWriter writer = resp.getWriter();//输出数据writer.write("Hello");//得到字节输出流ServletOutputStream out = resp.getOutputStream();// 输出数据out.write("Hi".getBytes());}
}

启动服务器,在浏览器中访问,只得到了第一个的打印内容
在这里插入图片描述
这是为什么呢?查看报错信息
在这里插入图片描述原来是getWriter()已经调用过response对象了,如果再响应一次response对象就已经不存在了

三、响应乱码问题

在上一节中我们使用request.setCharacterEncoding("UTF-8");解决了请求时中文乱码的问题,同样,在响应时也存在中文乱码问题。这是因为服务器响应的数据也会经过网络传输,服务器端有一种编码方式,在客户端也存在一种编码方式,当两端使用的编码方式不同时则出现乱码。

字符流乱码

对于getWriter()获取到的字符流,响应中文必定出乱码,由于服务器端在进行编码时默认会使用ISO-8859-1格式的编码,该编码方式并不支持中文。要解决该种乱码只能在服务器端告知服务器使用一种能够支持中文的编码格式,这也是我们在解决请求时中文乱码的方法

response.setCharacterEncoding("UTF-8");

此时还只完成了一半的工作
要保证数据正确显示,还需要指定客户端的解码方式

response.setHeader("content-type", "text/html; charset=UTF-8");

两端指定编码后,乱码就解决了。一句话:保证发送端接收端编码一致

实例
我们在start.java的service()中写入测试测试代码,试图打印中文

// 获取字符输出流
PrintWriter writer = resp.getWriter();
//输出数据
writer.write("汤米尼克");

启动服务器,在浏览器中访问,发现输出中文乱码
在这里插入图片描述
设置服务器和客户端的编码格式统一

// 设置服务端的编码
resp.setCharacterEncoding("UTF-8");
// 设置客户端的响应类型及编码
resp. setHeader("content-type", "text/html; charset=UTF-8");
// 获取字符输出流
PrintWriter writer = resp.getWriter();
// 输出数据
writer.write("汤米尼克");

重启浏览器,再在浏览器中访问就解决问题了
在这里插入图片描述
理解了原理,其实我们还可以同时设置客户端和服务端的编码方式

response.setContentType( "text/html; charset=UTF-8");

这一句就可以替换上面的两句

字节流乱码

对于getOutputStream()方式获取到的字节流,响应中文时,由于本身就是传输的字节,所以此时可能出现乱码,也可能正确显示。当服务器端给的字节恰好和客户端使用的编码方式一致时则文本正确显示,否则出现乱码。无论如何我们都应该准确掌握服务器和客户端使用的是那种编码格式,以确保数据正确显示。
因此,字节流乱码的解决方式与上面字符流乱码的解决方式一样,在响应发出之前同时设置服务器和客户端的编码格式统一即可

response.setContentType( "text/html; charset=UTF-8");

四、重定向:sendRedirect

重定向是一种服务器为指导的客户端行为
怎么理解这句话呢?客户端发出一个请求,被服务器接收处理后进行响应,在响应的同时,服务器会给客户端一个新的地址(下次请求的地址),当客户端接收到响应后,会立刻、马上自动根据服务器给的新地址发起第二个请求,服务器接收请求并作出响应,重定向完成。可以看出这个过程中有两个请求存在,其中两个Servlet的Request对象并不共享、不能传值,属于客户端行为。

在Servlet中重定向的语句为

response.sendRedirect("url");

实例:从start.java重定向到after.java的过程
在start.java的service()中写入重定向前的测试代码

System.out.println("这里是start");
resp.sendRedirect("after");

在after.java的service()中写入重定向到底测试代码

System.out.println("这里是after");

启动服务器,在浏览器中输入start的地址
在这里插入图片描述
回车访问后地址立即跳转到after,说明重定向的地址栏会发生改变
在这里插入图片描述
同时控制台输出了
在这里插入图片描述
那么重定向在服务器中的响应头是如何实现的?
如下图,在开发者工具中打开响应头的内容
在这里插入图片描述
会发现start文件响应行的状态码是302,这就是重定向的状态码
并且响应头键值对中Location键的值就是要重定向到的地址:after文件
这与我们在第一节 HTTP协议理论与服务器请求响应原理中学习的响应头的知识首尾呼应起来了

请求转发和重定向的区别

上一节中我们学习了Request对象的请求转发,这一节又学习了Response对象的重定向,两兄弟让人傻傻分不清,必须好好区分区分

请求转发重定向
request.getRequestDispatcher("url").forward(request, response);response.sendRedirect("url");
服务器端行为客户端行为
一次请求,Request域中数据共享两次请求,Request域中数据不共享
地址栏不发生变化地址栏发生变化
跳转只能在当前站点内跳转任意地址

在这一节中我们学习了HttpServletResponse对象,学习了字符流字节流响应方法、重定向方法。不禁思考,Servlet作为“后端”,在Web交互中最重要的作用就是传递各种数据,但目前我们学到的传值的方法还知之甚少,在下一节中我们将学习Cookie对象、HttpSession对象、ServletContext对象,它们作为不同特点的容器在Servlet上可以实现不同范围的传值

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.bcls.cn/DWdr/3262.shtml

如若内容造成侵权/违法违规/事实不符,请联系编程老四网进行投诉反馈email:xxxxxxxx@qq.com,一经查实,立即删除!

相关文章

数据库架构师之道:MySQL安装与系统整合指南

目录 MySQL数据库安装(centos) 版本选择 企业版 社区版 选哪个 MySQL特点 MySQL服务端-客户端 mysql下载选择 软件包解释 安装MySQL的方式 rpm包安装 yum方式安装 源码编译安装★ 具体的编译安装步骤★★ 环境准备 free -m命令 cat /pr…

Flutter GLSL - 肆 | 从条纹到马赛克

theme: cyanosis Flutter & GLSL 系列文章: 《Flutter & GLSL - 壹 | Shader 让绘制无限强大》《Flutter & GLSL - 贰 | 从坐标到颜色》《Flutter & GLSL - 叁 | 变量传参》《Flutter & GLSL - 肆 | 从条纹到马赛克》 案例代码开源地址 【skele…

C++学习之list容器

C++ list基本概念 在C++中,std::list是一个双向链表(doubly linked list)容器,它包含在 <list> 头文件中。下面是一些关于C++ std::list的基本概念: 双向链表结构:std::list是由多个节点组成的双向链表结构,每个节点包含数据元素和指向前一个节点和后一个节点的指…

树-王道-复试

树 1.度&#xff1a; 树中孩子节点个数&#xff0c;所有结点的度最大值为 树的度 2.有序树&#xff1a; 逻辑上看&#xff0c;树中结点的各子树从左至右是有次序的&#xff0c;不能互换。 **3.**树的根节点没有前驱&#xff0c;其他节点只有一个前驱 **4.**所有节点可有零个或…

wondows10用Electron打包threejs的项目记录

背景 电脑是用的mac&#xff0c;安装了parallels desktop ,想用electron 想同时打包出 苹果版本和windows版本。因为是在虚拟机里安装&#xff0c;它常被我重装&#xff0c;所以记录一下打包的整个过程。另外就是node生态太活跃&#xff0c;几个依赖没记录具体版本&#xff0…

Flink中的双流Join

1. Flink中双流Join介绍 Flink版本Join支持类型Join API1.4innerTable/SQL1.5inner,left,right,fullTable/SQL1.6inner,left,right,fullTable/SQL/DataStream Join大体分为两种&#xff1a;Window Join 和 Interval Join 两种。 Window Join又可以根据Window的类型细分为3种…

Kotlin 进阶版 协程

kotlin是协程的一种实现 Dispatchers.IO&#xff1a;适用于执行磁盘或网络 I/O 操作的调度器&#xff0c;例如文件读写、网络请求等。在 Android 中&#xff0c;Dispatchers.IO 会使用一个专门的线程池来处理这些操作&#xff0c;以防止阻塞主线程。 Dispatchers.Main&#xf…

RabbitMQ鉴权设计以及相关探讨

文章目录 1. rabbitmq的鉴权设计2. rabbitmq鉴权应用范围3. rabbitmq鉴权的常用方法3.1 用户管理3.2 角色管理3.3 权限管理 4. 默认鉴权4.1 默认用户4.2 默认角色 5. 参考文档 鉴权&#xff0c;分别由鉴和权组成 鉴&#xff1a; 表示身份认证&#xff0c;认证相关用户是否存在…

如何使用逻辑回归处理多标签问题?

逻辑回归处理多分类 1、背景描述2、One vs One3、One VS Rest4、从Sigmoid到Softmax的推导 1、背景描述 逻辑回归本身只能用于二分类问题&#xff0c;如果实际情况是多分类的&#xff0c;那么就需要对模型进行一些改动。下面介绍三种常用的将逻辑回归用于多分类的方法 2、One …

使用openai-whisper实现语音转文字

使用openai-whisper实现语音转文字 1 安装依赖 1.1 Windows下安装ffmpeg FFmpeg是一套可以用来记录、转换数字音频、视频&#xff0c;并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。 # ffmpeg官网 https://ffm…

【Crypto | CTF】BUUCTF RSA2

天命&#xff1a;密码学越来越难了&#xff0c;看别人笔记都不知道写啥 天命&#xff1a;莫慌&#xff0c;虽然我不会推演法&#xff0c;但我可以用归纳法 虽然我不知道解题的推演&#xff0c;但我可以背公式啊哈哈哈 虽然我不会这题&#xff0c;但是我也能做出来 公式我不知…

Qt事件过滤器

1. 事件过滤器 void QObject::installEventFilter(QObject *filterObj) bool eventFilter(QObject *obj, QEvent *event); filterObj表示事件筛选器对象&#xff0c;它接收发送到此QObject对象&#xff08;安装事件过滤器的部件对象&#xff09;的所有事件。筛选器可以停止事件…

LeetCode JS专栏刷题笔记(二)

一、前言 LeetCode - JavaScript 专栏刷题笔记第二篇。 第一篇刷题笔记详见&#xff1a;LeetCode JS专栏刷题笔记&#xff08;一&#xff09; 二、算法题目 1. 复合函数 LeetCode地址&#xff1a;2629. 复合函数 请你编写一个函数&#xff0c;它接收一个函数数组 [f1, f2, …

SQL-FEFT JOIN (拼接表)

语法 SELECT column_name(s) FROM table1 LEFT JOIN table2 ON table1.column_nametable2.column_name; 按照一定规则&#xff0c;将表table1和表table2拼接起来。 例&#xff1a; Employees 表&#xff1a; ------------------------ | Column Name | Type | ------…

挑战!贪吃蛇小游戏的实现(3)

经过&#xff08;1&#xff09;&#xff08;2&#xff09;两篇文章的介绍&#xff0c;相信大家对该游戏的实现已经有了具体的思路&#xff0c;废话不多说&#xff0c;让我们开始实现相关的代码吧&#xff01; 1.游戏主逻辑 void test() {int ch 0;srand((unsigned int)time(NU…

【Linux系统化学习】动静态库 | 软硬链接

目录 硬链接和软链接 硬链接 软链接 动态库和静态库 静态库 静态库的生成 静态库的使用 将库打包和使用 动态库 动态库的生成 动态库的使用 库搜索路径 硬链接和软链接 硬链接 上篇文章我们说到真正找到磁盘上的文件并不是文件名&#xff0c;而是inode。其实在…

【Appium UI自动化】pytest运行常见错误解决办法

通过Appium工具录制代码在pycharm上运行报错&#xff1a; 错误一&#xff1a; 1.提示 setup() 方法运行 error failed 解决办法&#xff1a;未创建 init __ 方法&#xff0c;创建一个空的__init.py文件就解决了。 原因&#xff1a; 错误二&#xff1a; 2.运行代码&#xff…

解决SpringAMQP工作队列模型程序报错:WARN 48068:Failed to declare queue: simple.queue

这里写目录标题 1.运行环境2.报错信息3.解决方案4.查看解决之后的效果 1.运行环境 使用docker运行了RabbitMQ的服务器&#xff1a; 在idea中导入springAMQP的jar包&#xff0c;分别编写了子模块生产者publisher&#xff0c;消费者consumer&#xff1a; 1.在publisher中运行测试…

PostgreSQL 的实体化视图介绍

PostgreSQL 实体化视图提供一个强大的机制&#xff0c;通过预先计算并将查询结果集存储为物理表来提高查询性能。本教程将使用 DVD Rental Database 数据库作为演示例子&#xff0c;指导你在 PostgreSQL中创建实体化视图。 了解实体化视图 实体化视图是查询结果集的快照&…

【ECharts】调用接口获取后端数据的四种方法

使用eacharts做大屏&#xff0c;需要使用后端数据&#xff0c;下面的方法是自己试过有效的&#xff0c;有什么不对的&#xff0c;望各位大佬指点。 目录 方法一&#xff1a;在mounted中使用定时器调用eacharts方法&#xff08;定时器可以获取到data中的数据&#xff09; 方法…
推荐文章