Servlet 之请求,响应,缓存以及乱码

时间:2022-12-14 11:36:59

  JavaWeb中,Servlet的请求,响应对象有很多实用的api,此处依据http协议中请求行,请求头,请求体以及响应行,响应头,响应体的思路,对这些api以及相关事项做个整理,最后总结一下乱码的相关处理。

  • 响应行

  响应行格式为"协议 状态码 状态码信息",这里主要就是状态码的操作,如果是比较正式的写法,应该使用HttpServletResponse接口中所定义的状态码,如:

    setStatus(404)
    setStatus(HttpServletResponse. SC_NOT_FOUND)
  • 响应头

  响应头所包含的内容比较多,大体上也分为三类,一类是参数为整形的,一类是参数为字符的,还有一类是参数为时间,所以对应的也有三个api:

setHeader(java.lang.String name, java.lang.String value) 设置指定的头,一般常用。--例如:setHeader("location","http://www.itheima.com");
setDateHeader(java.lang.String name, long date) 设置时间的(new Date().getTime())
setIntHeader(java.lang.String name, int value) 设置整形--例如:setIntHeader("expires", 1000) 设置过期时间的(缓存页面时间),如果0表示不缓存。现代浏览器不好使。

   如果这个响应头中包含了多种内容,还有:

response.addCookie(new Cookie("", ""));
response.addDateHeader("", new Date().getTime());
response.addHeader("", "");
response.addIntHeader("", 0);
  • 响应体

  后篇中详细分析。

  • 请求行

  对于Servlet的开发来说,请求request一般是获得的信息,属于输入,而响应response是处理的内容,需要输出。所以request我们的重点在于如何将浏览器发过来的请求获取到,请求行的内容主要包括"请求方法 请求资源?请求内容 协议",所以这其中如何获取到方法,资源以及请求内容便是重点:

  主要api:

/**
 * 实际访问路径   http://localhost:8080/day08/Demo05Servlet?username=jack&password=1234
 *
 */
//1 统一资源标记符  。例如: /day08/Demo05Servlet
String uri = request.getRequestURI();
System.out.println(uri);

//2统一资源定位符:例如:http://localhost:8080/day08/Demo05Servlet
StringBuffer url = request.getRequestURL();
System.out.println(url);
//3 协议和版本 ,  例如: HTTP/1.1
String protocol = request.getProtocol();
System.out.println(protocol);
//协议,例如: http
String scheme = request.getScheme();
System.out.println(scheme);

//4 主机(域名) , 例如:localhost ,如果使用ip地址,就显示ip
String serverName = request.getServerName();
System.out.println(serverName);

//5 端口 , 例如:8080
int port = request.getServerPort();
System.out.println(port);

//6 发布到tomcat下的项目名称 
String contextPath = request.getContextPath();
System.out.println(contextPath);

//7 servlet路径 , 例如:/Demo05Servlet
String servletPath = request.getServletPath();
System.out.println(servletPath);

//8 所有请求参数,及?之后所有 ,例如: username=jack&password=1234
String queryString = request.getQueryString();
System.out.println(queryString);
//9远程主机的ip地址
String remoteAddr = request.getRemoteAddr();
System.out.println(remoteAddr);
  • 请求头

  获取指定或所有的请求头:

String getHeader(java.lang.String name) 获得指定头内容String 例如:request.getHeader("referer");
long getDateHeader(java.lang.String name) 获得指定头内容Date
int getIntHeader(java.lang.String name)  获得指定头内容int
Enumeration getHeaders(java.lang.String name) 获得指定名称所有内容
  • 请求体 -- 获取参数
请求参数:
get请求参数:http://localhost:8080/day08/Demo07Servlet?username=jack&password=1234
post请求参数: <form method="post"><input type="text" name="username">
String request.getParameter(String) 获得指定名称,一个请求参数值。
String[] request.getParameterValues(String) 获得指定名称,所有请求参数值。例如:checkbox、select等
Map<String , String[]> request.getParameterMap() 获得所有的请求参数。map.key : 请求参数名称,map.value : 名称对应的所有参数值。

-------------------------------------分  割  线-------------------------------------->

  之前遗留了响应体,在此单独处理,是因为有一个重要的内容,即乱码问题,需要在此处详细说明。

  首先,在ServletResponse接口中定义了两个方法,ServletOutputStream getOutputStream()以及PrintWriter getWriter()这两个方法,分别对应了字节流与字符流,都提供了print(),write()方法,需要注意的是所有的print(args)方法在底层都调用了write(args)方法。

  如果我们发送中文数据,使用字符流(getWriter());如果使用二进制数据,那么使用字节流(getOutputStream()),例如下载等。一般情况下,使用流必须关闭,但在Servlet中可以不关闭,tomcat会在请求结束时自动关闭该流。

  >>当我们使用字节流向页面输送中文时,print(String s)方法会报异常:

java.io.CharConversionException: Not an ISO 8859-1 character: 中文字符

所以使用字节流无法用print(String)方法传送中文,但可以用write(byte[])将中文字符拆成指定编码格式的字节发送:

ServletOutputStream sos = response.getOutputStream();
sos.write("中文字符".getBytes("UTF-8"));

此时有可能乱码 -- tomcat发送的字节,tomcat本身没有处理,是否乱码取决于浏览器查看方式编码。

  >>当我们使用字符流向页面输送文字时,由于tomcat默认的编码方式为ISO-8859-1,所以必须在之前向tomcat声明使用"UTF-8"来处理字符:

response.setCharacterEncoding("UTF-8");

到这里,我们从tomcat流出的字符都是"UTF-8"格式的,但浏览器具体是什么编码格式,是不是符合"UTF-8"还是不可控的,所以这里我们可以强制浏览器的编码格式为"UTF-8"

方式一:
response.setHeader("content-type", "text/html;charset=UTF-8");
方式二:
response.setContentType("text/html;charset=UTF-8");

  ==>所以不管是字符还是字节,我们统一使用如下编码,可以保证输出中文时,不出乱码:

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

-------------------------------------分  割  线-------------------------------------->

  这里提一下请求参数的乱码问题,如果是post请求,那么我们需要做的是保持请求发送页面编码与处理该请求的编码一致即可,也就是说,页面上的

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

要在接收到请求时,用HttpServletRequest.setCharacterEncoding("UTF-8")来与请求页面的编码保持一致;如果是get请求,它的请求内容是放在请求行中,所以setCharacterEncoding(charset)方法无法让tomcat解决这个问题,所以需要在获取到请求内容后,先用"ISO-8859-1"转换字节,再根据页面编码重新组装:

String username = new String(request.getParameter("username").getBytes("ISO-8859-1"),"UTF-8");

-------------------------------------分  割  线-------------------------------------->

  response中使用流向浏览器发送数据,首先数据将写入 数据流的缓存中,但缓存大小8k时,将自动刷新到浏览器。对于不满缓存总量大小的数据,我们有以下api可以控制是否将缓存中的数据发送到浏览器中:

isCommitted()  缓存是否刷新过
flushBuffer() 手动的刷新 输出缓存
getBufferSize() 获得大小
resetBuffer() 清空缓存