HttpServletResponse对象

HttpServletResponse对象

介绍

​ Web 服务器收到客户端的 http 请求,会针对每一次请求,分别创建一个用于代表请求的 request 对象和代表响应的 response 对象。

​ request 和 response 对象代表请求和响应:获取客户端数据,需要通过 request 对象;向客户端 输出数据,需要通过 response 对象

HttpServletResponse 的主要功能用于服务器对客户端的请求进行响应,将 Web 服务器处理后的结果返回给客户端。service()方法中形参接收的是 HttpServletResponse 接口的实例化对象,这个对象 中封装了向客户端发送数据、发送响应头,发送响应状态码的方法。

常用方法

常用方法描述
addHeader(String name, String value)添加指定的键值到响应头信息中
containsHeader(String name)判断响应的头部是否被设置
encodeURL(String url)编码指定的 URL
sendError(int sc)使用指定状态码发送一个错误到服务端
setStatus(int sc)用来设定回应的状态码
sendRedirect()设置重定向页面
getWriter()取得PrintWriter对象,输出字符流
getOutputStream()获取输出的字节流
setContentType(String ContentType)设置响应的MIME类型

刷新和页面自动跳转

所有头信息都是随着请求和回应自动发送到服务器端(客户端),在 response 中一个比较常用的头信息就是刷新的指令,可以完成定时刷新的功能。

		//定时刷新
        resp.setHeader("refresh","10");

​ 对于刷新的头信息,除了定时的功能外,还具备了定时跳转的功能,可以让一个页面定时跳转到一个指定的页面。(已经注册成功,两秒后跳转到登陆页面)

		response.setHeader("refresh","3;URL=ok.html");

但是这种跳转不是万能的,有时候根本就无法进行跳转操作,返回后刷新不会跳转;对于这种定时跳转的头信息,也可以采用 HTML 的方式进行设置,HTML 本身也可以设置头信息。(客户端跳转)

		<meta http-equiv="refresh" content="3;http://www.baidu.com" />

数据响应

接收到客户端请求后,可以通过 HttpServletResponse 对象直接进行响应,响应时需要获取输出流,有两种形式 getWriter() 获取字符流 (只能响应回字符);getOutputStream()获取字节流(能响应

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

PrintWriter out = resp.getWriter(); 
out.write("<h1>Hello World</h1>"); 
ServletOutputStream out = resp.getOutputStream(); 
out.write("<h1>Hello World</h1>").getBytes());

乱码解决

我们会发现在上述的响应中,如果我们响应的内容中含有中文,则有可能出现乱码。这是因为服务 器响应的数据也会经过网络传输,服务器端有一种编码方式,在客户端也存在一种编码方式,当两端使用的编码方式不同时则出现乱码。

getWriter() 的字符乱码

对于 getWriter() 获取到的字符流,响应中文必定出乱码,由于服务器端在进行编码时默认会使用 ISO-8859-1 格式的编码,该编码方式并不支持中文。
所以要解决该种乱码只能在服务器端告知服务器 使用一种能够支持中文的编码格式,比如我们通常用的“UTF-8” resp.setCharacterEncoding("UTF- 8");,此时还只完成了一半的工作,要保证数据正确显示,还需要指定客户端的解码方式

resp.setHeader(“content-type”, “text/html;charset=UTF-8”);,和服务器一致。两端指定编码 后,乱码就解决了。一句话:保证发送端和接收端的编码一致

resp.setCharacterEncoding("UTF-8"); 
resp.setHeader("content-type", "text/html; charset=UTF-8"); 
PrintWriter out = resp.getWriter(); 
out.write("<h1>你好啊!!!!</h1>");

以上两端编码的指定也可以使用一句替代,同时指定服务器和客户端

resp.setContentType("text/html;charset=utf-8");

对于 getOutputStream() 方式获取到的字节流,响应中文时,由于本身就是传输的字节,所以此时 可能出现乱码,也可能正确显示,这就看人品了_。当服务器端给的字节恰好和客户端使用的编码方 式一致时则文本正确显示,否则出现乱码。无论如何我们都应该准确掌握服务器和客户端使用的是那种 编码格式,以确保数据正确显示。指定客户端和服务器使用的编码方式一致即可。

resp.setHeader(“content-type”, “text/html;charset=UTF-8”);。

resp.setHeader("content-type", "text/html; charset=UTF-8"); 
ServletOutputStream out = resp.getOutputStream(); 
out.write("<h1>你好啊!!!</h1>".getBytes("UTF-8"));

同样也可以使用一句替代

resp.setContentType("text/html;charset=utf-8");

总结:要想解决响应的乱码,只需要保证使用支持中文的编码格式。并且保证服务器端 和客户端使

用相同的编码方式即可。

响应图片

在学习 HTML 的时候我们知道使用 的方式可以显示图片。但有的时候我们 并不知道(或不能确定)图片的路径,需要通过请求服务器资源动态地响应图片给客户端。这种方式和文 件拷贝的理念是一致的,客户端请求服务器的资源,在服务端获取到真实的图片资源,通过输入流读取 到内存,然后通过输出流写出到客户端即可。

值得注意的是,在客户端解析资源时默认是以文本(text/html)的形式,当响应图片时需要指定响 应头信息,告知客户端响应内容为图片形式,使用一种叫做 MIME 类型的东西来指定。MIME 类型见 Tomcat 的 web.xml 文件。

<mime-mapping>
	<extension>jpeg</extension>
    <mime-type>image/jpeg</mime-type> 
</mime-mapping> 
<mime-mapping> 
	<extension>jpg</extension> 
	<mime-type>image/jpeg</mime-type> 
</mime-mapping> 
<mime-mapping> 
	<extension>jpgm</extension> 
	<mime-type>video/jpm</mime-type>
</mime-mapping> 
<mime-mapping> 
	<extension>jpgv</extension>
    <mime-type>video/jpeg</mime-type> 
</mime-mapping> 
<mime-mapping> 
	<extension>jpm</extension> 
	<mime-type>video/jpm</mime-type> 
</mime-mapping>

定义某一个扩展名和某一个 MIME Type 做对应,包含两个子元素:

<extension></extension> 扩展名的名称

MIME 格式

// 得到图片名称 
String name = "tree.jpg";
// 得到图片存放在服务器上的真实路径 String filePath = req.getServletContext().getRealPath("/WEB-INF/image/" + name); System.out.println(filePath);
// 通过路径得到file对象 
File file = new File(filePath); 
// 判断file对象是否存在,并且是一个标准文件 
if(file.exists() && file.isFile()){ 		
	resp.setContentType("image/jpeg;charset=utf-8"); 
	// 判断图片的格式
	// 得到图片的后缀 
	String pic = name.split("\\.")[0]; 
	// 判断是否为空 
	if(pic == null || "".equals(pic)){ 
        return; 
    }
    // 根据不同的图片类型设置MIME响应类型 
    if("png".equals(pic)){ 
        resp.setContentType("image/png;charset=utf-8"); 
    }else if("gif".equals(pic)){ 
        resp.setContentType("image/gif;charset=utf-8"); 
    }else if("jpg".equals(pic) || "jpeg".equals(pic)){ 											resp.setContentType("image/jpeg;charset=utf-8"); }
    // 得到文件的输入流 
    FileInputStream in = new FileInputStream(file); 
    // 得到输出流 
    ServletOutputStream out = resp.getOutputStream(); 
    byte[] car = new byte[1024]; 
    int len = 0; 
    while((len = in.read(car)) != -1){ 
        // 输出 
        out.write(car, 0, len); 
    }
    // 关闭流 
    in.close(); 
    out.close(); 
} else { 
    PrintWriter out = resp.getWriter(); out.write("<h1>文件路径不正确!</h1>"); 
}

重定向跳转

重定向是一种服务器指导客户端的行为。客户端发出第一个请求,被服务器接收,经过处理服务器 进行响应,与此同时,服务器给客户端一个地址(下次请求的地址 resp.sendRedirect(“url”);),当客 户端接收到响应后,立刻、马上、自动根据服务器给的地址进行第二个请求的发送,服务器接收请求并 作出响应,重定向完成。从描述中可以看出重定向当中有两个请求存在,并且属于客户端行为。实现方式如下:

resp.sendRedirect("index.html")

通过观察浏览器我们发现第一次请求获得的响应码为 302,并且含有一个 location 头信息。并且地 址栏最终看到的地址是和第一次请求地址不同的,地址栏已经发生了变化。

请求转发和重定向比较:

请求转发(req.getRequestDispatcher().forward()重定向(resp.sendRedirect()
一次请求,数据在 request 域中共享两次请求,request 域中数据不共享
服务器端行为客户端行为
地址栏不发生变化地址栏发生变化
绝对地址定位到站点后绝对地址可写到 http://

在请求资源时,必须给出正确的路径,否则是找不到资源的。路径分为相对路径和绝对路径,绝对路径可简单理解为完整路径,在 web 项目中绝对路径分两种,一种是以 http:// 开头的,该种绝对路径 已经跨域,即任何地方的资源都能访问,另一种则是从当前域名|IP|主机后的端口号开始的,不能跨域,也属于一种绝对路径。相对路径则就是相对当前资源所在路径。

我们学的所有的请求可以分为客户端和服务器端请求两类(不考虑ajax);

相对路径

书写路径时,无论是哪类请求相对路径都是相对当前资源的路径

书写格式:直接从当前路径开始写,目录前不加任何符号;a.html html/b.html

相对路径在请求转发时可能会失效,因此开发中不推荐使用相对路径

绝对路径

使用绝对路径时则有两种方式,以 http:// 开头,或者以 / 开头,但是注意:只有客户端跳转才能 使用 http:// 这种方式,此时需要写出资源的完整路径;另一种以 / 开头的绝对路径,则是绝对到端口 后,例如本机则是:http://localhost:8080 此时则是 / 代表以上一串字符。
/helloworld/a.html → http://localhost:8080/helloworld/a.html

浏览器中:“/”代表的是 http://主机|IP:端口

服务器中:“/”代表的是 http://主机|IP:端口/站点名

现在对于我们来说,只有请求转发属于服务器跳转,其他都是客户端跳转。通过观察地址栏状态也 可判定跳转类型(请求类型),地址栏不变 → 服务器端跳转;地址栏改变 → 客户端跳转。

Cookies

Cookie 是浏览器提供的一种技术,通过服务器的程序能将一些只须保存在客户端,或者在客户端 进行处理的数据,放在本地的计算机上,无论何时用户链接到服务器,Web 站点都可以访问 Cookie 信息不需要通过网络传输,因而提高网页处理的效率,并且能够减少服务器的负载,但是由于 Cookie 是服务器端保存在客户端的信息,所以其安全性也是很差的。例如常见的记住密码则可以通过 Cookie 来实现。

有一个专门操作Cookie的类 javax.servlet.http.Cookie。随着服务器端的响应发送给客户端,保存在浏览器。当下次再访问服务器时把 Cookie 再带回服务器。

Cookie 的格式:键值对用 “ = ” 链接,多个键值对间通过 “ ; ” 隔开

Cookie 剖析

Cookie 通常设置在 HTTP 头信息中(虽然 JavaScript 也可以直接在浏览器上设置一个 Cookie)。设置 Cookie 的 Servlet 会发送如下的头信息:

HTTP/1.1 200 OK
Date: Fri, 04 Feb 2000 21:03:38 GMT
Server: Apache/1.3.9 (UNIX) PHP/4.0b3
Set-Cookie: name=xyz; expires=Friday, 04-Feb-07 22:03:38 GMT; 
                 path=/; domain=runoob.com
Connection: close
Content-Type: text/html

Set-Cookie 头包含了一个名称值对、一个 GMT 日期、一个路径和一个域。名称和值会被 URL 编码。expires 字段是一个指令,告诉浏览器在给定的时间和日期之后"忘记"该 Cookie。

如果浏览器被配置为存储 Cookie,它将会保留此信息直到到期日期。如果用户的浏览器指向任何匹配该 Cookie 的路径和域的页面,它会重新发送 Cookie 到服务器。浏览器的头信息可能如下所示:

GET / HTTP/1.0
Connection: Keep-Alive
User-Agent: Mozilla/4.6 (X11; I; Linux 2.2.6-15apmac ppc)
Host: zink.demon.co.uk:1126
Accept: image/gif, */*
Accept-Encoding: gzip
Accept-Language: en
Accept-Charset: iso-8859-1,*,utf-8
Cookie: name=xyz

Servlet 就能够通过请求方法 request.getCookies() 访问 Cookie,该方法将返回一个 Cookie 对象的数组。

Servlet Cookie 方法

序号方法 & 描述
1public void setDomain(String pattern) 该方法设置 cookie 适用的域,例如 runoob.com。
2public String getDomain() 该方法获取 cookie 适用的域,例如 runoob.com。
3public void setMaxAge(int expiry) 该方法设置 cookie 过期的时间(以秒为单位)。如果不这样设置,cookie 只会在当前 session 会话中持续有效。
4public int getMaxAge() 该方法返回 cookie 的最大生存周期(以秒为单位),默认情况下,-1 表示 cookie 将持续下去,直到浏览器关闭。
5public String getName() 该方法返回 cookie 的名称。名称在创建后不能改变。
6public void setValue(String newValue) 该方法设置与 cookie 关联的值。
7public String getValue() 该方法获取与 cookie 关联的值。
8public void setPath(String uri) 该方法设置 cookie 适用的路径。如果您不指定路径,与当前页面相同目录下的(包括子目录下的)所有 URL 都会返回 cookie。
9public String getPath() 该方法获取 cookie 适用的路径。
10public void setSecure(boolean flag) 该方法设置布尔值,表示 cookie 是否应该只在加密的(即 SSL)连接上发送。
11public void setComment(String purpose) 设置cookie的注释。该注释在浏览器向用户呈现 cookie 时非常有用。
12public String getComment() 获取 cookie 的注释,如果 cookie 没有注释则返回 null。

Cookie的创建和发送

通过 new Cookie(“key”,”value”); 来创建一个 Cookie 对象,要想将 Cookie 随响应发送到客户端,需要先添加到 response 对象中, resp.addCookie(cookie); 此时该 cookie 对象则随着响应发送至了客户端。在浏览器上可以看见。

// 创建Cookie对象 
Cookie cookie = new Cookie("A", "aa"); 
// 响应给客户端
resp.addCookie(cookie);

Cookie 的获取

在服务器端只提供了一个 getCookies() 的方法用来获取客户端回传的所有 cookie 组成的一个数组,如果需要获取单个 cookie 则需要通过遍历,getName() 获取 Cookie 的名称,getValue()获取 Cookie 的值。

// 获取客户端的Cookie数组 
Cookie[] cookies = req.getCookies(); 
// 判断是否为空 
if(cookies != null && cookies.length > 0){ 
	// 遍历 
	for (Cookie cookie : cookies) { 
		// 键名称 
		String name = cookie.getName(); 
		// 值 
		String value = cookie.getValue(); 		  	 
        System.out.println("键:" + name + ",值:" + value); 
      } 
 }

Cookie 到期时间的设定

从图中除了看到 Cookie 的名称和内容外,我们还需要关心一个信息,到期时间,到期时间用来指定该 cookie 何时失效。默认为当前浏览器关闭即失效。我们可以手动设定 cookie 的有效时间(通过到期时间计算),通过 setMaxAge(int expiry); 方法设定 cookie 的最大有效时间,以为单位。

大于 0 的整数,表示存储的秒数;若为负数,则表示不存储该 cookie;若为 0,则删除该cookie。

负整数:cookie 的 maxAge 属性的默认值就是 -1,表示只在浏览器内存中存活,一旦关闭浏览器窗口,那么 cookie 就会消失。

正整数:表示 cookie 对象可存活指定的秒数。当生命大于 0 时,浏览器会把 Cookie 保存到硬盘上,就算关闭浏览器,就算重启客户端电脑,cookie 也会存活相应的时间。

:cookie 生命等于 0 是一个特殊的值,它表示 cookie 被作废!也就是说,如果原来浏览器已经保存了这个 Cookie,那么可以通过 Cookie 的 setMaxAge(0) 来删除这个 Cookie。 无论是在浏览器内存中,还是在客户端硬盘上都会删除这个 Cookie。

Cookie的注意

在一般的站点中常常有记住用户名这样一个操作,该操作只是将信息保存在本机上,换电脑以后这些信息就无效了。而且 cookie 还不能跨浏览器。

Cookie 中不能出现中文,如果有中文则通过 URLEncoder.encode() 来进行编码,获取时通过URLDecoder.decode() 来进行解码。

String name = "姓名"; 
String value = "张三"; 
name = URLEncoder.encode(name, "utf-8"); 
value = URLEncoder.encode(value, "utf-8"); 
Cookie cookie = new Cookie(name, value); resp.addCookie(cookie); 
Cookie[] cookies = req.getCookies(); 
if(cookies != null){ 
	for(Cookie coo:cookies){ 
		String name = URLDecoder.decode(coo.getName(), "utf-8"); 
		String value = URLDecoder.decode(coo.getValue(), "utf-8"); 
		System.out.println(name + ":" + value); 
		} 
}

不同的浏览器对 Cookie 也有限定,Cookie 的存储是有上限的。Cookie 是存储在客户端(浏览器)的,而且一般是由服务器端创建和设定。后期结合 Session 来实现会话跟踪。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值