Servlet Response的常用方法 缓存和乱码处理

news2024/11/28 21:59:24

前言

Servlet Response相关的信息,在service方法中使用的是HttpServletResponse,它继承自ServletResponse,扩展了Http协议相关的内容,下面简单记录一下它的基本用法。

一、response组成内容

以下是一个常见response响应的内容,它包括状态行、响应头、一个空行和实体内容,其中"HTTP/1.1 200 OK"就是状态行,包括协议、状态代号和状态描述信息,下面有若干响应头,空行和实体内容。

 HTTP请求中的常用响应头如下:

1 Location: http://www.it315.org/index.jsp 配合302实现请求重定向

2 Server:nginx服务器类型

3 Content-Encoding: gzip 服务器发送数据的压缩格式

4 Content-Length: 80 发送数据的长度

5 Content-Language: zh-cn 发送数据的语言环境

6 Content-Type: text/html; charset=GB2312 可接受数据格式和语言

7 Last-Modified: Tue, 11 Jul 2018 17:20:51 GMT 与请求头的if modified头呼应,主要跟缓存有关

8 Refresh: 1;url=http://www.sdedu.org 定时刷新

9 Content-Disposition: attachment;filename=ab.zip 跟下载有关,下载文件名字ab.zip

10 Set-Cookie:SS=Q0=5Lb_nQ; path=/search

11 Expires: -1 通知浏览器是否缓存当前资源,如果这个头的值是一个以毫秒为单位的值,就是通知浏览器缓存资源到指定的时间点,如果值是0或-1则是通知浏览器禁止缓存。

12 Cache-Control: no-cache 通知浏览器是否缓存的头,no-cache代表不缓存

max-age=0和no-cache的区别:no-cache强制直接向源服务器请求不经过缓存服务器,而max-age=0需要经过缓存服务器。等于0时,缓存服务器需要将请求转发给源服务器。

13 Connection: close/Keep-Alive 连接状态

14 Date:  Sat, 30 Mar 2024 14:40:10 GMT   Date可以用来判断是否来自缓存

Response的方法,就是针对响应内容进行的,它可以设置状态码、设置响应头,设置响应内容。

二、response常用方法 

response提供了常用的api,有如下三类,通过它可以实现response的许多功能。

1、设置状态码

设置状态码有如下API

       response.setStatus(int status) 设置状态码

代码实现:

/**
 * 设置状态码
 */
@WebServlet("/ResponseDemo01")
public class ResponseDemo01 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置404
        response.setStatus(404);
        response.getWriter().write("Hello Status");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

访问页面后发现尽管能正常访问到资源,但是状态码被设置成了404。

2、设置响应头

设置影响头的方法,可以影响到页面的效果,有时候需要和上面设置状态码的方法配合使用,它常用的方法:

(1)void setHeader(String name, String value)  用给定名称和值设置响应头。如果已经设置了头,则新值将重写以前的值。

(2)void setIntHeader(String name, int value) 此方法的默认行为是对包装的响应对象调用 addIntHeader(String name, int value)。 

下面简单了解一下setIntHeader方法,这个方法可以用在设置页面刷新频率,设置发送数据的长度等。

代码实现:

/**
 * 设置使用setIntHeader方法
 */
@WebServlet("/ResponseDemo02")
public class ResponseDemo02 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置刷新
        /* response.setIntHeader("Refresh",5);
        response.getWriter().write("<font color='blue' size='10px'>this is setIntHeader method"+"+"+Math.random()*100+"</font>");*/
        //设置发送数据长度,一个英文字符代表1个长度
        response.setIntHeader("Content-Length",8);
        response.getWriter().write("Hello World");

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

实际效果,会每隔5秒刷新一次页面

另外setIntHeader里如果设置Content-length,还可以控制输出到页面的数据长度,发现输出到页面的实际长度被截取了。

3、设置响应消息

有两种方法可以设置响应消息,如下。

(1)ServletOutputStream getOutputStream() 

(2)PrintWriter getWriter()  

上文中的response.getWriter().write("Hello Status"),就使用了PrintWriter。

三、response常用功能

response常用功能有请求重定向、控制缓存、页面刷新等。

请求重定向
1、请求重定向

请求重定向的原理就是设置状态码为302,并且在响应头里设置location的路径,就可以实现重定向,也可以直接使用现成api来实现。

/**
 * 请求重定向
 */
@WebServlet("/ResponseDemo03")
public class ResponseDemo03 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //原理实现
        //设置状态码
        response.setStatus(302);
        //设置消息头
        response.setHeader("Location","http://www.baidu.com");

        //api实现
        //以上代码等效如下代码
        //response.sendRedirect("http://www.baidu.com");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

访问ResponseDemo03后页面跳转到百度,重定向的地址是会改变的。

2、控制缓存

控制缓存有三个api可以使用,可以通过设置影响头的Cache-Control、Pragma和Expires来控制,参考前面对响应头的介绍和如下代码。

/**
 * 浏览器缓存的设置
 */
@WebServlet("/ResponseDemo04")
public class ResponseDemo04 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置不使用缓存
        /*public void setDateHeader(String name, long date)
        用给定名称和日期值设置响应头。该日期根据距历元时间的毫秒数指定。如果已经设置了头,则新值将重写以前的值。
        containsHeader 方法可用于测试在设置其值之前头是否存在。*/
        //方式1
        if(response.containsHeader("Expires")){
            response.setDateHeader("Expires",-1);
        }
        //方式2
        response.setHeader("Cache-Control","no-cache");
        //方式3
        response.setHeader("Pragma","no-cache");

        Date date=new Date();
        String time = date.toLocaleString();
        //设置使用缓存
        //response.setDateHeader("Expires",System.currentTimeMillis()+1000*60*60*1);//1 hour
        //response.setHeader("Cache-Control","max-age=60");//60 s

        response.getWriter().write("<font color='blue'>"+time+"</font>");


    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

当不使用缓存时,每次刷新一下页面,就会打印新的时间。当设置完使用缓存,在缓存的寿命范围内,时间都不会变的,目前在IE和火狐浏览器测试可以,chrome可能没有效果。

3、页面刷新 

页面刷新可以设置响应头的Refresh,里面一个时间参数单位为秒,一个刷新后页面的url地址,注意使用url,这个可以用在注册后隔几秒跳转到主页这种场景。以下代码就是实现访问ResponseDemo05请求后,等待3秒会刷新进入百度主页的功能。


/**
 * 定时刷新
 */
@WebServlet("/ResponseDemo05")
public class ResponseDemo05 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //3 秒后 刷新进入百度主页
        response.setHeader("Refresh","3;url=http://www.baidu.com");
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

四、response乱码处理

response响应,可能会导致有服务器和浏览器编解码不一致的问题,并会产生乱码,接下来使用字节流和字符流发送数据,查看乱码情况,使用如下基准代码进行调试,根据测试条件做调整即可。

/**
 * 响应字节流和字符流的乱码处理
 */
@WebServlet("/ResponseDemo06")
public class ResponseDemo06 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1 字节流
        System.out.println(response.getCharacterEncoding());
        //ISO-8859-1 tomcat默认的字符编码,针对字符流,对字节流无影响
        //response.getOutputStream().write("china".getBytes());
        //getByte()默认使用平台的字符编码,即GBK,而浏览器默认使用GBK解码,因此没有乱码
        //response.getOutputStream().write("中国".getBytes());
        /**
         * 一般浏览器都会设置utf-8解码,这里需指定服务器编码方式为utf-8,设置浏览器解码也是utf-8
         */
        //通知浏览器使用utf-8来解码
        response.setHeader("Content-Type","text/html;charset=utf-8");
        response.getOutputStream().write("中国".getBytes("utf-8"));

        //2 字符流
        //默认使用iso-8859-1将字符流转变成字节流,底层由Tomcat服务器来完成,会使用Tomcat默认的字符集
        //通知服务端发送数据时字符集utf-8
        //response.setCharacterEncoding("utf-8");
        //如果告诉浏览器使用何种字符集,则这句可以不用写,服务会在发送数据自动采用浏览器设置的字符集
        //通知浏览器指定utf-8读取
        //response.setHeader("Content-Type","text/html;charset=utf-8");

        //也可以用如下api
        //response.setContentType("text/html;charset=utf-8");
        //response.getWriter().write("我是英文");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}
1、字节流发送数据

使用字节流发送数据使用ServletOutputStream的write方法,使用发现在不设置任何编码格式的情况下,浏览器能正常显示中文,并没有乱码产生,通过查看响应头发现也没有指定Content-Type。

这是因为用getByte方法得到字节数组时,使用的是平台默认的字符集,即GBK,而当不指定浏览器解码字符集时也是使用平台默认的字符集GBK,两者一致因此没有产生乱码。 

一般浏览器会使用utf-8来解码,因此需要使用如下代码指定浏览器的解码字符集,以及服务器的编码字符集均为utf-8。

response.setHeader("Content-Type","text/html;charset=utf-8");
response.getOutputStream().write("中国".getBytes("utf-8"))

 修改后发现响应头里有指定Content-Type。

2、字符流发送数据

使用字符流发送数据使用PrintWriter的write方法,在不设置字符集的情况下,发现'我是英文'四个字显示四个问号,产生了乱码问题。

 这是因为字符流本质上还是会转化为字节流,当服务器不指定字符编码时,会默认使用tomcat的字符编码,即ISO-8859-1,而浏览器不指定解码时默认使用GBK,因此会产生乱码,另外ISO-8859-1是单字节编码无法表示中文。

想要解决乱码问题也是通过统一编码方式,服务端使用setCharacterEncoding的方法指定,浏览器字符集有两种方法指定,两种都可以,本质上就是设置响应头里的Content-Type。

//默认使用iso-8859-1将字符流转变成字节流,底层由Tomcat服务器来完成,会使用Tomcat默认的字符集
//通知服务端发送数据时字符集utf-8
response.setCharacterEncoding("utf-8");
//如果告诉浏览器使用何种字符集,则这句可以不用写,服务会在发送数据自动采用浏览器设置的字符集
//通知浏览器指定utf-8读取
//response.setHeader("Content-Type","text/html;charset=utf-8");

//也可以用如下api
response.setContentType("text/html;charset=utf-8");

修改后浏览器就能正常显示中文了。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【二叉树】Leetcode 114. 二叉树展开为链表【中等】

二叉树展开为链表 给你二叉树的根结点 root &#xff0c;请你将它展开为一个单链表&#xff1a; 展开后的单链表应该同样使用 TreeNode &#xff0c;其中 right 子指针指向链表中下一个结点&#xff0c;而左子指针始终为 null 。展开后的单链表应该与二叉树 先序遍历 顺序相同…

Linux(CentOS7)配置系统服务以及开机自启动

目录 前言 两种方式 /etc/systemd/system/ 进入 /etc/systemd/system/ 文件夹 创建 nginx.service 文件 重新加载 systemd 配置文件 ​编辑 配置开机自启 /etc/init.d/ 进入 /etc/init.d/ 文件夹 创建 mysql 文件 编写脚本内容 添加/删除系统服务 配置开机自启 …

如何使用Java语言发票查验接口实现发票真伪查验、票据ocr

随着时代潮流的发展&#xff0c;企业也在寻找更加便捷、高效的办公模式&#xff0c;尤其是针对财务工作人员而言&#xff0c;繁琐的发票录入、查验工作占据了财务人员的大部分时间。对此&#xff0c;翔云提供了发票识别接口、发票查验接口&#xff0c;那么企业应当如何将这些接…

笔记本三屏异显方案——更新中,是否能够在FPGA上实现,淘宝购物的价格太贵

三屏是&#xff08;笔记本电脑屏幕&#xff0c;两个显示器屏幕&#xff09;&#xff0c;异显是采用屏幕的扩展功能&#xff0c;这样能够左边看视频文章&#xff0c;右边control cv代码。 一、 电脑有一个HDMI口的时候&#xff0c;只需要买一个TypeC&#xff08;雷电接口&#x…

AI大模型在金融行业的应用场景和落地路径

作者&#xff1a;林建明 来源&#xff1a;IT阅读排行榜 本文摘编自《AIGC重塑金融&#xff1a;AI大模型驱动的金融变革与实践》&#xff0c;机械工业出版社出版这是最好的时代&#xff0c;也是最坏的时代。尽管大模型技术在金融领域具有巨大的应用潜力&#xff0c;但其应用也面…

STM32八种I/O口模式

STM32八种I/O口模式 文章目录 STM32八种I/O口模式前言一、stm32八种I/O类型二、区别1.模拟输入2.浮空输入3.上拉输入4.下拉输入5.推挽输出6.开漏输出7.复用推挽输出8.复用推挽输出 总结 前言 作为两年嵌入式软件攻城狮&#xff0c;还没仔细去理解过STM32的GPIO的八种使用模式&…

【蓝桥杯第十三届省赛B】(部分详解)

九进制转十进制 #include <iostream> #include<math.h> using namespace std; int main() {cout << 2*pow(9,3)0*pow(9,2)2*pow(9,1)2*pow(9,0) << endl;return 0; }顺子日期 #include <iostream> using namespace std; int main() {// 请在此…

Vue.js基础指令

(在讲指令之前,可以先了解插值表达式,如果已经知道,当我没说) 一.插值表达式 1.数据绑定最常见的形式就是双大括号的文本插值,Mustache上属性的值替代。只要绑定的数据对象上属性发生了改变,插值处的内容都会更新。,message 是将数据解析成纯文本的,也就是说,就算中…

BM19 寻找峰值(二分查找)

import java.util.*; public class Solution {/*** 代码中的类名、方法名、参数名已经指定&#xff0c;请勿修改&#xff0c;直接返回方法规定的值即可** * param nums int整型一维数组 * return int整型*/public int findPeakElement (int[] nums) {// write code hereint lef…

Thread 之start 和run 的区别

Java Thread 之start 和run 的区别 用start方法来启动线程&#xff0c;真正实现了多线程运行&#xff0c;这时无需等待run方法体代码执行完毕而直接继续执行下面的代码。通过调用Thread类的start()方法来启动一个线程&#xff0c;这时此线程处于就绪&#xff08;可运行&#x…

持续交付与持续部署相关概念(CD)

目录 一、概述 二、持续交付基本概念 2.1 持续交付的含义 2.1.1 项目管理的视角 2.1.2 产品研发的视角 2.1.3 总结 2.2 持续交付涉及的运作环境 2.2.1 开发环境 2.2.2 测试环境 2.2.3 UAT环境 2.2.4 准生产环境 2.2.5 生产环境 2.3 总结 三、持续部署基本概念 3.…

数据结构八大常见的排序

数据结构八大常见的排序 常见排序算法分类1.插入排序2.希尔排序(缩小增量排序)3.选择排序4.堆排序5.冒泡排序6.快速排序7.归并排序归并排序非递归的实现8.计数排序 常见排序算法分类 1.插入排序 基本思想&#xff1a;把待排序的数组按大小逐个插入到一个已经排好序的有序序列中…

【Java EE】多线程(一)

&#x1f4da;博客主页&#xff1a;爱敲代码的小杨. ✨专栏&#xff1a;《Java SE语法》 | 《数据结构与算法》 | 《C生万物》 |《MySQL探索之旅》 |《Web世界探险家》 ❤️感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;&#xff0c;您的三连就是我持续更…

物联网实战--入门篇之(六)嵌入式-WIFI驱动(ESP8266)

目录 一、WIFI简介 二、基础网络知识 三、思路讲解 四、代码分析 4.1 状态机制 4.2 客户端连接 4.3 应用数据接收处理 4.4 数据发送 4.5 主函数调用 4.6 网络连接ID分配 五、总结 一、WIFI简介 WIFI在我们生活中太常见了&#xff0c;手机电脑都可以用WiFi连接路由器进行上…

MIT最新研究成果 机器人能够从错误中纠偏 无需编程介入和重复演示

目前科学家们正在努力让机器人变得更加智能&#xff0c;教会他们完成诸如擦拭桌面&#xff0c;端盘子等复杂技能。以往机器人要在非结构化环境执行这样的任务&#xff0c;需要依靠固定编程进行&#xff0c;缺乏场景通用性&#xff0c;而现在机器人的学习过程主要在于模仿&#…

开关恒流源简介

目录 工作原理 设计要点 应用场景 初步想法&#xff0c;为参加活动先占贴&#xff08;带家人出去玩没时间搞~~&#xff09;&#xff0c;后面优化 开关恒流源是一种基于开关电源技术的恒流输出电源设备。它采用开关管进行高速的开关动作&#xff0c;通过控制开关管的导通和截…

linux 一些命令

文章目录 linux 一些命令fdisk 磁盘分区parted 分区文件系统mkfs 格式化文件系统fsck 修复文件系统 mount 挂载swap 交换分区清除linux缓存df du 命令raid 命令基本原理硬raid 和 软raid案例raid 10 故障修复&#xff0c;重启与卸载 lvm逻辑卷技术LVM的使用方式LVM 常见名词解析…

数据库---------完全备份和增量备份的数据恢复,以及断点恢复

目录 一、在数据库表中&#xff0c;分三次录入学生考试成绩 1.1先创建库&#xff0c;创建表&#xff0c;完成三次数据的录入 1.2首次录入成绩后&#xff0c;做该表的完全备份 1.3第二次插入后 做增量备份 1.4第三次插入后 做增量备份 二、模拟数据丢失&#xff0c;并使用…

大文件上传做断点续传(有详细的代码内容)

文章目录 一、是什么分片上传断点续传 二、实现思路三、使用场景小结参考文献 一、是什么 不管怎样简单的需求&#xff0c;在量级达到一定层次时&#xff0c;都会变得异常复杂 文件上传简单&#xff0c;文件变大就复杂 上传大文件时&#xff0c;以下几个变量会影响我们的用户…

标题:Vue3 中父组件向子组件通信的方式

标题&#xff1a;Vue3 中父组件向子组件通信的方式 在 Vue3 中&#xff0c;父组件和子组件之间可以通过一些方式进行通信。其中&#xff0c;父组件向子组件通信主要有两种方式&#xff1a;传值和调用子组件的方法。 一、父组件向子组件传值 当父组件需要向子组件传递数据时&a…