Servlet基础知识(HTTP相关)

这篇主要讲的是 Request 和 Response 的一些基本使用
还有就是 Cookie 和 Session 的使用

关于 Servlet API 的介绍,可移步到这里:JavaEE 复习计划

Request和Response

请求和响应,使用频率应该是非常高的,我目前也是初学者,对这两大对象了解的也不多,当然会尽量让内容丰满起来滴

Request

它就是请求,带着用户的一些请求信息而来,常用的方法有:

  • getParamenterNames(key)
    获取用户提交过来的参数的名字,返回一个枚举,GET 和 POST 都可以使用,然后可以根据名字来获得值

  • getParameter()
    很显然,这是获取指定提交参数名字(key)的值

  • getParameterMap()
    获取一个 Map 集合类型的参数集合,可以用一些库通过反射技术直接拷贝到 javabean 里面去
    返回值是 Map<String, String[]>

  • getHeader(key)
    可能会用到,请求头也有些有用的信息,返回的是全部的请求头信息

  • setAttribute( key,val )
    设置自定义参数,除了获取值还可以设置值,可以通过转发等方式继续向下传递

  • setCharacterEncoding()
    设置 request 的编码,解决中文乱码问题,提交中文数据的时候是按当前网页的码表进行提交,但是 request 的默认码表未必是你设置的码表,所以就会有乱码,所以要先设置一下
    当然改服务器的配置也是可以的,但是不推荐
    但是这个方法只对 POST 请求方式有效,GET 方式出现中文要进行URL编码,内容都在 URL 中,还有其实各个浏览器默认编码也不统一,对于 GET 方式的处理方式:

    1
    2
    3
    4
    5
    // setCharacterEncoding 方法和 getCharacterEncoding 方法只对请求体起作用
    String name = request.getParameter("name");
    // 第一个参数是 Tomcat 编码,第二个是浏览器编码
    name = new String(name.getBytes("iso8859-1"),"utf-8");
    System.out.println(name);

    至于为什么要使用 getBytes("iso-8859-1"),是因为在你浏览器用某种编码后,Servlet 容器自作多情给你用 iso-8859-1 解码了一下,所以….只能原路返回
    在 Tomcat8 + 的版本,官方已使用 UTF-8 编码,不存在这个问题了

  • getRequestDispatcher(“path”).forward(request,response)
    这就是我们经常写的请求转发
    一个请求只能往客户机写出一次,当 clos 以后就不能再写了,所以转发后别关呀
    同样转发也是写数据,所以只能转发一次,为了避免报错,所以转发后最好写个 return
    转发时会把以前写的数据(Response中)清空

  • getRequestDispatcher(“path”).include(request,response);
    包含界面,也很常用,需要注意的是,被包含页面不要写全部的 html 标签,因为是整个文件包含进来,所以只写主体部分就可以了

  • getInputStream()
    获取流,一般上传文件的时候会用到

Response

相比 Request 来说 Response 的使用就比较简单了,当然说的是常规使用
通常我们会设置:setContentType("text/html;charset=utf-8");
它其实相当于两句,设置响应头和 response 对象的默认编码

1
2
3
4
// 设置resp使用什么码表,往里写字符流的时候,建议还是写上,清晰点
resp.setCharacterEncoding("UTF-8");
// 设置响应头
resp.setHeader("content-type","text/html;charset=utf-8");

然后就是使用 sendRedirect() 进行重定向
至于 getOutputStream 和 getWriter 方法我就不多说了,就是一个字节流一个字符流,使用字符流要注意编码,他们两个不能同时使用

如果是下载文件的需求或者存在中文记得要进行 URL编码 后再设置到 header。
再说缓存问题,通过设置头信息可以禁止浏览器缓存:

1
2
3
4
5
//不允许浏览器端或缓存服务器缓存当前页面信息。
response.setHeader("Pragma", "No-cache");
//浏览器和缓存服务器都不应该缓存页面信息
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);

但是需history要注意的是浏览器的后退按钮直接走的 history 缓存,默认是不刷新页面的。

Cookie和Session

至于它们是什么,什么用,在以前的文章 HTTP笔记中 已经说的很清楚了,不多说,一句话概况就是用来管理会话的

一段代码说明问题,简单的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 获取用户的cookie
Cookie[] cookies = request.getCookies();
for (int i = 0; cookies != null && i < cookies.length; i++) {
if (cookies[i].getName().equals("time")){
long time = Long.parseLong(cookies[i].getValue());
Date date = new Date(time);
writer.println(date.toLocaleString());
}
}

// 设置新的 cookie
Cookie cookie = new Cookie("time",System.currentTimeMillis()+"");
// 设置有效期 单位:秒 如果设为 0 表示清除,负数表示关闭浏览器失效,path一定要一致
cookie.setMaxAge(24*3600);
// 如果不设置,默认是当前页面有效
cookie.setPath("/webapp");

response.addCookie(cookie);

重点是 path 的默认值,通过看源码就很明白了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//...............其他代码................
for (String headerValue : responseHeaders.get(headerKey)) {
try {
List<HttpCookie> cookies = HttpCookie.parse(headerValue);
for (HttpCookie cookie : cookies) {
if (cookie.getPath() == null) {
// If no path is specified, then by default
// the path is the directory of the page/doc
String path = uri.getPath();
if (!path.endsWith("/")) {
int i = path.lastIndexOf("/");
if (i > 0) {
path = path.substring(0, i + 1);
} else {
path = "/";
}
}
cookie.setPath(path);
}
// ...............其他代码................

可以总结为:

  • 当 cookie 的 path 设置了值不为 null 的时候,以设置的值为准。
  • 当 cookie 的 path 为 null 时候,获取请求的 URI 的 path 值。
    • 当 URI 的 path 值是以 / 结尾的时候,直接设置为 cookie 的 path 值
    • 当 URI 的 path 值不是以 / 结尾的时候,查看 path 里面是否有“/”
      如果有“/”的话,直接截取到最后一个“/”,然后设置为 cookie 的 path 值。
      如果没有“/”的话,将 cookie 的 path 设置为 /

然后就是不要忘记父域可以访问子域的 cookie。

Session

同样是一段代码就可以说明问题,简单使用,Session 还是会用到 Cookie的,默认情况下它会以一个固定的名字(Jsessionid)将ID存储到 Cookie,然后,以后的请求就会带有这个 Cookie,也就 SessionID,SessionID 也可以理解为是 Cookie 中特殊的一个值,它默认不设置有效期,也就是浏览器关闭就会失效
如果需要自定义有效期有手动进行覆盖(其实就是设置此 Cookie 的有效期),记得设 path
一般情况下都要对这个 ID 进行加密处理的,同时,一个浏览器独占一个 Session

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
HttpSession session = request.getSession();
// 还可以接受一个参数,用来控制如果没有的话是否创建
// request.getSession(false);

// session 域传递参数,数据存在服务器
session.setAttribute("key","data");
session.setAttribute("token","base64-md5");

/*
当浏览器禁用 Cookie 的时候,使用 URL 进行传输 Session ID
第一次请求会返回一个带 SessionID 的URL,
当检测到下一次请求带有Cookie的时候,表示Cookie没有被禁用,以后就不再更改 URL
然后把此 url 设置给 a 标签之类的就可以了
*/
String strURL = response.encodeURL("/JavaWeb/xx");

// session.invalidate(); 手动销毁

如果仅仅是简单使用的话,其实只用第一行代码就足够了
想要手动设置 Session 的期限的话,需要造一个 Cookie 然后把那个 SessionID 写进去,相当于覆盖了原先的,然后设个时间;这样是为了用户关闭浏览器后再打开的时候还可以保持以前的状态,当然这个时间一般最多也就是半小时,因为默认半小时后 SessionID 就被服务器给回收了,带过去也没用

1
2
3
4
5
6
7
HttpSession session = request.getSession();
String id = session.getId();
// 设置 Cookie 相同的 key 进行覆盖
Cookie cookie = new Cookie("JSESSIONID", id);
cookie.setPath("/JavaWeb"); // 不要忘记
cookie.setMaxAge(30 * 60);
response.addCookie(cookie);

不过有些浏览器的版本(IE)是按进程来区分的,就是说你同时打开两个浏览器的窗口 Session 是共享的
选项卡直接是共享的,这个任何浏览器都没问题

在 web.xml 中可以控制 Session 的回收时间、默认名称等,在 <session-config> 标签设置
如果启用了 HTTPS 那么 SessionID 完全可以使用 SSLSessionID ,毕竟在握手的时候就创建了一个密钥了

作用

Cookie 可以用来实现 记住密码 的功能,当然要进行加密处理,也可以保存一下其他的不是很重要的信息,因为毕竟它保存在客户端,其实就是一个文本文件,可以人为的进行修改,不安全

Session 一般用来记录用户的登陆状态,这个放在服务器端比较好,不管是从安全方面还是设计方面
还可以用来防止表单的重复提交,给表单加一个隐藏域来保存 id 参数,同时也存一份在 Session 中,然后提交的时候先判断带过来的 id 是否合法,就是与 Session 中的进行比较,如果合法就删除掉,然后处理请求,如果不合法直接 return 哼

关于生成的唯一 id,或者叫令牌 Token,一般最后要进行摘要算法进行处理(比如用 MD5),变成固定长度的数据,但是这个数据是二进制的,不能直接搞成字符串,所以再进行 Base64 进行编码,这样一般就没问题了
PS:了解 Base64 是什么看左边菜单的科普

补充

对于四大域(ServletContext 、Request 、Session、PageContext)的使用:

数据显示后就没用了,使用 Request 域,比如 Servlet 传给 JSP 进行显示
数据显示后还要用,使用 Session 域
数据显示后还要用,并且还要给别人用,那就使用 context 域

关于地址的写法,遵循:
如果地址是给服务器用的 /代表 Web 应用
如果是给浏览器用的 / 代表网站(就是 webapps),网站下有多个应用

喜欢就请我吃包辣条吧!

评论框加载失败,无法访问 Disqus

你可能需要魔法上网~~