Response&Request
2017-05-26 本文已影响0人
明天你好向前奔跑
Response&Request
一、介绍
Web服务器每收到一次http请求,针对每一个请求,都会创建一个代表请求的request对象和
一个代表响应的response对象。Response其实就是响应客户端请求的对象。它可以用来给客户端写数据。
二、作用
1 : 写响应行
setStatus(int sc) : 设置状态码
2 : 写响应头
**sendRedirect(String location)** : 请求重定向
setHeader(String name,String value) : 设置响应头信息
// 告知客户端不缓存
response.setHeader("pragma","no-cache");
response.setHeader("cache-control","no-cache");
response.setDateHeader("expires",0);
// 设置多少秒后刷新到指定路径的页面
response.setHeader("refresh","count;url");
3 : 写响应体
**getWriter()** : 获取当前response对象的字符输出流
getOutputStream() : 字节输出流
三、解决中文乱码问题
因为服务器响应默认写出编码是 ISO-8859-1 , 与客户端解析的编码不一致 , 会导致中文乱码。
解决方案一:
//告诉服务器Tomcat以utf-8编码写出去
response.setCharacterEncoding("utf-8");
//告诉客户端(浏览器)以utf-8编码解析相应回去的内容
response.setHeader("Content-Type", "text/html;charset=utf-8");
解决方案二:
//这种方法封装了上面两个方法,包含了上面两个方法的意思
response.setContentType("text/html;charset=utf-8");
Request
一、介绍
Request是代表客户端请求的一个对象,用于对请求进行操作的对象。
二、作用
下面以在http://localhost:8080/WebTest/index.html
的提交表单测试以下方法
1 : 存 | 取数据
request.setAttribute(name,value)
request.getAttribute(name)
2 : 获取请求消息行信息
**request.getContextPath() : 获取当前项目的路径
request.getRequestURL() : 获取
request.getRequestURI()
request.getMethod() : 获取请求提交的方式
request.getProtacal() : 获取请求使用的协议版本
request.getremoteHost() : 获取访问的地址
......
测试:
// Request获取消息行信息的方法:
System.out.println(request.getContextPath()); /WebTest
System.out.println(request.getMethod()); POST
System.out.println(request.getRequestURL()); http://localhost:8080/WebTest/demo
System.out.println(request.getRequestURI()); /WebTest/demo
System.out.println("=========================");
getQueryString()只能获得拼在地址栏get方式提交的数据
System.out.println(request.getQueryString()); username=jerry&password=123&password=123
System.out.println(request.getProtocol()); HTTP/1.1
System.out.println(request.getRemoteAddr()); 0:0:0:0:0:0:0:1
System.out.println(request.getRemoteHost()); 0:0:0:0:0:0:0:1
System.out.println(request.getRemoteUser()); null
3 : 获取请求消息头信息
**request.getHeader(name) : 获取指定消息头的信息
request.getHeaderNames(name) : 获取指定属性名的所有消息头,返回Enumeration枚举项数组
request.getHeaders(name) : 获取消息头字段为name的所有消息头。返回Enumeration枚举项
-------------------------------------------
request.getDateHeader()
request.getIntHeader()
// Request获取消息头信息的方法:
// 获取单个信息头的值:request.getHeader(name)
System.out.println(request.getHeader("User-Agent"));
System.out.println("-----------------------------");
结果:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3013.3 Safari/537.36
//获取消息头为指定名称的多个值
//request.getHeaders(name)
// 获取所有的信息头的名称:request.getHeaderNames()
Enumeration<String> names = request.getHeaderNames();
while (names.hasMoreElements()) {
// 遍历获取每一个消息头名称:
String name = (String) names.nextElement();
// 获取每一个信息头对应的值:
String header = request.getHeader(name);
System.out.println(name + " : " + header);
}
测试结果.png
4 : 获取请求提交的参数的信息
**request.getParameter(name) : 获得参数名为name的单个参数的值
request.getParameterNames() : 获得提交数据的所有参数名,返回Enumeration对象
**request.getParameterMap : 将请求消息的所有参数的名称和值存放入一个map集合中,并返回map集合
---------------------------------------------------------
request.getParameterValues(name) : 获得参数名为name的所有参数的值,返回String数组
测试:
// Request获取参数的方法:
// 获取单个参数:request.getParameter(name)
System.out.println(request.getParameter("username"));
System.out.println("=============================");
// 获取参数名相同的多个参数值:
String[] values = request.getParameterValues("password");
System.out.println(Arrays.toString(values));
System.out.println("=============================");
// 获取所有参数名
Enumeration<String> names = request.getParameterNames();
while (names.hasMoreElements()) {
// 获取每一个参数名
String name = (String) names.nextElement();
// 获取每一个参数名对应的值
String value = request.getParameter(name);
System.out.println(name + " : " + value);
}
System.out.println("=============================");
// 获取所有的参数与参数值的map集合
Map<String, String[]> parameterMap = request.getParameterMap();
// 增强for遍历map集合,输出参数名和他的值
for (Entry<String, String[]> set : parameterMap.entrySet()) {
String key = set.getKey();
String[] strings = set.getValue();
if (strings.length == 1) {
System.out.println(key + "---" + strings[0]);
} else {
System.out.println(key + "---" + Arrays.toString(strings));
}
}
测试结果.png
5 : request对象处理中文乱码问题
客户端提交数据有时候会有中文,而在客户端(如浏览器)的HTML页面默认以UTF-8的编码进行解码,将提交的数据
解析成二进制,但是当服务器(Tomcat)接收到提交的数据后,服务器会以默认的编码:ISO-8859-1编码,因此会
出现中文乱码现象。处理乱码GET请求和POST请求的处理方式如下:
-
POST请求提交中文到服务器
请求对象中告诉服务器以UTF-8进行编码: request.setCharacterEncoding("UTF-8")
-
GET请求
服务器通过getParameter(name)获得的参数经过ISO-8859-1编码,将它重新变为byte字节数组,然后UTF-8的格式重新编码 例如: filename = new String(filename.getBytes("ISO-8859-1"),"UTF-8");
还是以上面的页面进行测试:
Get请求.png在姓名输入框中输入:林志玲
在没有进行中文处理之前,点击确定显示乱码
GET请求结果.png
GET方式处理乱码:
//获取要处理的参数username
System.out.println(request.getMethod());
String username = request.getParameter("username");
//将以ISO-8859-1编码的username参数重新以UTF-8编码
username = new String(username.getBytes("ISO-8859-1"),"UTF-8");
System.out.println(username);
System.out.println("=============================");
GET中文2乱码处理后.png
POST方式处理乱码:
//告诉服务器以指定格式的编码进行编码
request.setCharacterEncoding("UTF-8");
System.out.println(request.getMethod());
System.out.println(request.getParameter("username"));
POST请求处理后.png
三、作用域
request对象是在服务器接收到请求时,在service()方法调用之前就创建了,在服务器对客户端做出响应之后销毁。
-
生命周期
- 创建:
- 产生一个请求时创建request对象
- 销毁
- 服务器对客户端做出响应后
- 创建:
正是由于request对象生命周期,也决定了request对象的作用域只能在当次请求有效。
因此它与ServletContext不同,ServletContext的作用域在当前项目下都有效。
四、页面跳转(重定向与请求转发)
1、 重定向
由response对象处理,响应给客户端,让它跳转页面
原始版本:
//告诉客户端要进行重定向操作
response.setHeader(302);
//告诉客户端要跳转的页面
response.setHeader("Location",url);
封装后:
response.sendRedirect(url);
重定向请求图解
2、请求转发
由request对象处理。
请求转发:
request.getRequestDispatcher(url).forward(ServletRequest req,ServletResponse resp);
请求包含:(相当于把后面那个页面的代码追加到前面这个页面)
request.getRequestDispatcher(url).include(ServletRequest req,ServletResponse resp);
请求转发的请求图解
五、案例
1:下载服务器文件位置在Resource中的资源
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// System.out.println(this.getServletContext().getRealPath(""));
// D:\Develop\apache-tomcat-7.0.52\wtpwebapps\day16_DownLoadDemo
// 默认访问的是服务器当前项目的根目录
// 1.点击下载发送请求,就会将其要下载的文件路径发送过来,使用request获取要下载资源的文件名
String filename = request.getParameter("filename");
System.out.println("文件名处理前:"+filename);
// 1.1 获取要下载文件的类型,现在浏览器会帮忙处理
String mimeType = this.getServletContext().getMimeType(filename);
response.setHeader("Content-Type", mimeType);
System.out.println(mimeType);
request.setCharacterEncoding("UTF-8");
//让服务器与客户端使用的编码一致
response.setContentType("UTF-8");
// 2.下载文件
// 获取到的filename参数是通过GET方式发送的,为了防止中文乱码
filename = new String(filename.getBytes("ISO-8859-1"), "utf-8");
System.out.println("文件名处理后:"+filename);
// 通过资源的相对路径获得该资源的全路径
String realPath = this.getServletContext().getRealPath("Resource/" + filename);
// 为了在下载时能够使中文能正确在浏览器的URL栏正确显示,需要对filename再做一次URL编码处理
// 获取浏览器的信息
String agent = request.getHeader("User-Agent");
System.out.println(agent);
// Firefox使用的是Base64的编码,而IE和谷歌等下载中文文件时使用的是URL编码
if (agent.toLowerCase().contains("firefox")) {
filename = base64EncodeFileName(filename);
} else {
filename = URLEncoder.encode(filename,"UTF-8");
}
//设置下载时的确认框Content-Dispositon
response.setHeader("Content-Dispositon", "attachment;filename="+filename);
//获取输入流
InputStream is = new FileInputStream(realPath);
//获取输出流
ServletOutputStream os = response.getOutputStream();
int len = 0;
byte[] bys = new byte[1024];
while ((len = is.read(bys)) != -1) {
os.write(bys, 0, len);
}
os.close();
is.close();
}
public static String base64EncodeFileName(String fileName) {
BASE64Encoder base64Encoder = new BASE64Encoder();
try {
return "=?UTF-8?B?" + new String(base64Encoder.encode(fileName.getBytes("UTF-8"))) + "?=";
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
文件下载案例.png
2:使用验证码工具包完成验证码更换功能
Servlet响应类:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//导入验证码工具jar包,ValidateCode.jar
//创建获取验证码对象
ValidateCode validateCode = new ValidateCode(120, 40, 4, 12);
//获取验证码,可以用于与用户校对
//String code = validateCode.getCode();
//谁发送请求过来,就将验证码写给谁
validateCode.write(response.getOutputStream());
}
Html页面:
难点:
-
除了每次访问页面会发送一次请求,src和href也会发送一次请求,他们发送请求到Servlet,服务器对其做出响应。
-
为了实现点击验证码图片能够完成更换验证码功能,为其添加了onclick点击事件,但会发现点击一次之后就不再变化了,这是因为浏览器缓存了验证码图片。在请求的地址后面添加参数,让其每次的请求地址都不同,这样就可以避免这个问题。
-
在后面添加a标签:看不清换一张。如果直接在a标签中绑定点击事件href即使不填,也会跳到一个新的空白页面。为了让其不跳转页面,
href="javascirpt:changeCode()"
。javascript的意思是告诉html页面href后面跟的不是url地址,让其直接调用changeCode()方法</div> <div class="col-sm-2"> ![](code) <a href="javascript:changeCode()">看不清,换一张</a> </div> <script type="text/javascript"> function changeCode() { //获取验证码图片元素 var image = document.getElementById("img01"); //让该验证码图片的地址改变,发送请求道Servlet(一般href和src都会发送一次请求) //为了防止浏览器读取缓存,为了让其网址每次都不同,加上new Date()作为参数 image.src="code?time="+new Date(); } </script>