Cookie技术详解
1. Cookie的特性
属性:
1> name: Cookie的名字
2> value: Cookie的值
3> path: 可选,Cookie的存储路径,默认情况下的存储路径时访问的Servlet所在的路径
4> MaxAge: 可选,最大的存活时间,默认情况下是存放在缓存区中的,生命周期是一个会话
5> version: Cookie的版本
6> domain: 域名(即网站)
7> Comment: 备注
下面我带大家来解读读J2EE1.5_API文档中对Cookie技术的说明
下面是我对文档的一点翻译(不准确的之处敬请指正):
Creates a cookie, a small amount of information sent by a servlet to a Web browser, saved by the browser, and later sent back to the server. A cookie's value can uniquely identify a client, so cookies are commonly used for session management.
创建一个cookie,servlet容器向浏览器发送一小段的信息,浏览器会存储这些信息,以后浏览器可以把这些信息发送回给服务器。一个cookie的值可以唯一的表示一个客户端,所以cookies通常被用来作为会话管理。
A cookie has a name, a single value, and optional attributes such as a comment, path and domain qualifiers, a maximum age, and a version number. Some Web browsers have bugs in how they handle the optional attributes, so use them sparingly to improve the interoperability of your servlets.
一个cookie包含一个名字、一个值、类似备注的可选属性、路径、域名、生命值和版本号。一些浏览器在处理可选属性的时候存在缺陷,所以要谨慎的使用它们来提高你的服务器的交互性(健壮性)。
The servlet sends cookies to the browser by using the HttpServletResponse.addCookie(javax.servlet.http.Cookie) method, which adds fields to HTTP response headers to send cookies to the browser, one at a time. The browser is expected to support 20 cookies for each Web server, 300 cookies total, and may limit cookie size to 4 KB each.
servlet容器通过 HttpServletResponse.addCookie(javax.servlet.http.Cookie) 这个方法向浏览器发送cookies,将字段添加到HTTP响应头来向浏览器发送 cookies,一次发送一个cookie。对于每个web服务器,浏览器支持20个cookies,浏览器一共可以支持300个cookies,可能会限制每个cookie的大小为4B.
The browser returns cookies to the servlet by adding fields to HTTP request headers. Cookies can be retrieved from a request by using the HttpServletRequest.getCookies() method. Several cookies might have the same name but different path attributes.
浏览器通过向HTTP请求头添加字段的方式把cookies返回给servlet容器。一个请求可以通过 HttpServletRequest.getCookies() 方法检索到cookies。一些cookies也许有相同的名字,但它们的属性却不相同。
Cookies affect the caching of the Web pages that use them. HTTP 1.0 does not cache pages that use cookies created with this class. This class does not support the cache control defined with HTTP 1.1.
使用Cookies时会影响网页的缓存。HTTP1.0中使用cookie创建的类不缓存页面。在HTTP1.1中cookie这个类不支持缓存控制。
This class supports both the Version 0 (by Netscape) and Version 1 (by RFC 2109) cookie specifications. By default, cookies are created using Version 0 to ensure the best interoperability.
这个类同时支持版本0(Netscape)和版本1(RFC 2109) cookie规范。默认情况下,使用版本0创建cookie,以确保最佳的互操作性。
2. 服务器发送Cookie给浏览器
HttpServletResponse.addCookie(javax.servlet.http.Cookie)
每个网站最多支持20个Cookie,总共支持最多300个,每个Cookie最大4kb. (Cookie的资源是非常稀少的,Cookie中存储的数据都是非常必要的重要的数据。)
3. 服务端如何获得浏览器所携带的Cookie
HttpServletRequest.getCookies()
4. 服务端如何删除Cookie
由于服务端没有提供删除的方法,因此采用创建相同的Cookie,设置存活时间为0的办法,覆盖已经存在的Cookie
5. 如何唯一的确定一个Cookie
域名+ 访问路径 + Cookie的名字
6. 浏览器到底带不带Cookie,谁说了算呢?
浏览器到底带不带Cookie是由浏览器说了算。
浏览器通过判断你在地址栏中敲入的资源地址. starWith(在硬盘上存储的Cookie里面存储的路径) 为true ,那就带,否则就不带.
7. 演示代码
演示了记录上次访问的时间
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8") ;
response.setContentType("text/html;charset=UTF-8") ;
PrintWriter out = response.getWriter() ;
out.write("您上次访问的时间是: ") ;
//拿到客户端携带的记录上次访问时间的Cookie : 假设Cookie的名字是lastaccesstime , 值是一个long类型的数字
//拿到客户端携带的所有的Cookie
Cookie[] cs = request.getCookies() ;
//循环判断拿到我们需要的Cookie
for (int i = 0; cs!=null && i < cs.length; i++) {
Cookie c = cs[i] ;
if(c.getName().equals("lastaccesstime")){
//说明找到了需要的Cookie
String time = c.getValue() ;
//将time转换成long类型的值
long t = Long.parseLong(time) ;
//格式化为我们需要的格式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss") ;
//创建一个date对象
Date d = new Date(t) ;
//将数据输出到页面上
out.write(sdf.format(d) + " <a href = '"+ request.getContextPath()+"/servlet/ServletCookie2'>清除Cookie</a>") ;
}
}
//向客户端发送Cookie
Cookie c = new Cookie("lastaccesstime",new Date().getTime() + "") ;
//设置Cookie的存活时间(只要设置了存活时间,那么此Cookie就将存储到客户端的硬盘上,不会在缓存中存储)
c.setMaxAge(Integer.MAX_VALUE) ;
//设置浏览器携带Cookie的路径
c.setPath(request.getContextPath()) ;
//设置路径如果是/,那就意味着你访问服务器上的任意工程资源都会携带此Cookie
//c.setPath("/") ; //设置路径是服务器的根路径 协议 + 主机名 + 端口号
//发送到客户端
response.addCookie(c) ;
}
}
删除客户端存储的Cookie
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//要想删除客户端存储的Cookie,sun公司没有提供相应的删除方法,
//所以采用的办法就是创建一个同名的cookie,将存活时间设置为0,然后覆盖客户端存储的Cookie
Cookie c = new Cookie("lastaccesstime","") ;
c.setMaxAge(0) ;
//设置路径
c.setPath(request.getContextPath()) ;
//发送到客户端
response.addCookie(c) ;
}
演示是否能够获取Cookie(演示path的含义)
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8") ;
response.setContentType("text/html;charset=UTF-8") ;
PrintWriter out = response.getWriter() ;
out.write("你上次访问的时间是") ;
//拿到客户端所有的Cookie
Cookie[] cs = request.getCookies() ;
//拿到记录上次访问时间的Cookie
for (int i = 0;cs!= null && i < cs.length; i++) {
Cookie c = cs[i] ;
if(c.getName().equals("lastaccesstime")){
String value = c.getValue() ;
out.write(value) ;
}
}
}
8. 记录用户名和密码案例
1> 创建登录页面
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8") ;
response.setContentType("text/html;charset=UTF-8") ;
PrintWriter out = response.getWriter() ;
//拿到错误信息
String name = (String) request.getAttribute("error") ;
if(name != null)
out.write("<font color = red>" + name + "</font>") ;
String username = "" ;
String pass = "" ;
//拿到客户端携带的所有的Cookie
Cookie[] cs = request.getCookies() ;
//循环判断
for (int i = 0; cs !=null && i < cs.length; i++) {
Cookie c = cs[i] ;
if(c.getName().equals("name")){
//说明找到了存储用户名的cookie
username = c.getValue() ;
}
if(c.getName().equals("pass")){
//说明找到了存储密码的Cookie
pass = c.getValue() ;
}
}
//创建登陆页面
out.write("<form action = '" + request.getContextPath()+"/servlet/LoginServlet' method = 'post'>") ;
out.write("姓名:<input type = 'text' name = 'username' value = '" + username + "'><br>") ;
out.write("密码:<input type = 'text' name = 'password' value = '" + pass + "'><br>") ;
out.write("<input type = 'checkbox' name = 'remeber' value = 'on'>记住用户名及密码两周<br>") ;
out.write("<input type = 'submit' value = '登陆'><br>") ;
}
2> 登录的逻辑判断
//向客户端发送清除或者记录用户名和密码的Cookie
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8") ;
response.setContentType("text/html;charset=UTF-8") ;
PrintWriter out = response.getWriter() ;
//拿取浏览器器传递的数据
String name = request.getParameter("username") ;
String pass = request.getParameter("password") ;
String remeber =request.getParameter("remeber") ;
//判断用户是否是合法用户 : 假定name和pass的逆序一样就是合法用户
//拿到密码的逆序
String pass1 = new StringBuffer(pass).reverse().toString() ;
//判断
if(name.equals(pass1)){
//是合法用户
//判断用户是否选择了记住用户名和密码
//说明用户选择了记录
Cookie c = new Cookie("name",name) ;
Cookie c1 = new Cookie("pass",pass) ;
if("on".equals(remeber)){
//设定存储到客户端的硬盘上
c.setMaxAge(Integer.MAX_VALUE) ;
c1.setMaxAge(Integer.MAX_VALUE) ;
}else{
//设定客户端存储的用户名和密码立刻失效
c.setMaxAge(0) ;
c1.setMaxAge(0) ;
}
//设定访问路径
c.setPath(request.getContextPath()) ;
c1.setPath(request.getContextPath()) ;
//向客户端发送Cookie
response.addCookie(c) ;
response.addCookie(c1) ;
request.setAttribute("name", name) ;
request.getRequestDispatcher("MainServlet").forward(request, response) ;
}else{
//非法用户
request.setAttribute("error", "用户名或者密码错误") ;
request.getRequestDispatcher("ServletUI").forward(request, response) ;
}
}
3> 登录成功的页面
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8") ;
response.setContentType("text/html;charset=UTF-8") ;
PrintWriter out = response.getWriter() ;
String name = (String) request.getAttribute("name") ;
out.write(name + ",欢迎你") ;
}
9. Cookie记住历史浏览记录
1> 创建Book模型
public class Book {
private String id ;
private String bookName ;
private String author ;
private float price ;
private String description ;
public Book(String id, String bookName, String author, float price,
String description) {
this.id = id;
this.bookName = bookName;
this.author = author;
this.price = price;
this.description = description;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public String toString() {
return "Book [id=" + id + ", bookName=" + bookName + ", author="
+ author + ", price=" + price + ", description=" + description
+ "]";
}
}
2> 创建Book的工具类
public class BookUtils {
private static Map<String,Book> map = new HashMap<String,Book>() ;
// 静态块,当加载此静态块的时候,书这个类就已经在里面了,模拟数据库中的数据
static{
map.put("1", new Book("1","葵花宝典","安倍晋三",100,"欲练神功,必须先练好基本功")) ;
map.put("2", new Book("2","辟邪剑谱","陈冠希",80,"绝世好书")) ;
map.put("3", new Book("3","西游记","吴承恩",50,"一群小猴子的故事")) ;
map.put("4", new Book("4","水浒传","施耐庵",90,"三个女人和105个男人的故事")) ;
map.put("5", new Book("5","西厢记","阿娇",70,"好好看啊。。。。。。")) ;
map.put("6", new Book("6","神雕侠侣","金庸",100,"感天动地的旷世绝恋")) ;
map.put("7", new Book("7","红楼梦","葫芦娃",60,"男人的梦想。。。。。。。")) ;
}
// 获取所有的书
public static Map<String,Book> getAllBook(){
return map ;
}
// 根据书的id获取谋一本书
public static Book getBookById(String id){
return map.get(id) ;
}
}
3> 显示所有的书
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8") ;
response.setContentType("text/html;charset=UTF-8") ;
PrintWriter out = response.getWriter() ;
out.write("本站有以下好书:<br>") ;
//1.显示所有的书
//获取所有的书的集合
Map<String ,Book> map = BookUtils.getAllBook() ;
//遍历集合
for (Map.Entry<String, Book> entry : map.entrySet()) {
//拿到每一本的id
String id = entry.getKey() ;
//拿到每一本书
Book book = entry.getValue() ;
//输出书的名字
out.write(book.getBookName() + " <a href = '"+ request.getContextPath()+"/servlet/ShowBookDetailServlet?id=" + id +"'>显示详细信息</a><br>") ;
}
out.write("<br><br><br><br>") ;
//2显示浏览的历史记录: 假设存放历史记录的Cookie的名字叫history : 值的形式: 1-2-3
//拿到客户端携带的所有的Cookie
Cookie[] cs = request.getCookies() ;
//循环判断
for (int i = 0; cs !=null && i < cs.length; i++) {
Cookie c = cs[i] ;
if("history".equals(c.getName())){
out.write("你的浏览历史记录如下: <br>") ;
//找到了存放历史记录的Cookie
String value = c.getValue() ;
//将字符串拆分成成数组
String[] ids = value.split("-") ;
//循环数组,拿到每一本书,显示在页面上
for (int j = 0; j < ids.length; j++) {
Book b = BookUtils.getBookById(ids[j]) ;
out.write(b.getBookName() + "<br>") ;
}
}
}
}
4> 显示书的详细信息
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8") ;
response.setContentType("text/html;charset=UTF-8") ;
PrintWriter out = response.getWriter() ;
//1.显示书的详细信息
//拿到页面传递的id
String id = request.getParameter("id") ;
//根据id获取书
Book book = BookUtils.getBookById(id) ;
//显示信息
out.write(book + " <a href = '" + request.getContextPath() +"/servlet/ShowAllBookServlet'>返回主页继续浏览</a><br>") ;
//2.发送历史浏览记录
//功能:获取历史记录字符串
String history = getHistory(request,id) ;
//创建Cookie,发送Cookie
Cookie c = new Cookie("history",history) ;
//设置Cookie存放到客户端的硬盘上
c.setMaxAge(Integer.MAX_VALUE) ;
//设置客户端携带Cookie的路径
c.setPath(request.getContextPath()) ;
//发送Cookie
response.addCookie(c) ;
}
/**
* 浏览器携带的历史记录的Cookie 点击的书的id 最终需要发送的字符串
* 1. 无 1 1
* 2. 1 1 1
* 3. 1 2 2-1
* 4. 1-2 1 1-2
* 5. 1-2 2 2-1
* 6. 1-2 3 3-1-2
* 7. 1-2-3 1 1-2-3
* 8. 1-2-3 2 2-1-3
* 9. 1-2-3 3 3-1-2
* 10. 1-2-3 4 4-1-2
*
*/
//获取要发往客户端的历史记录的字符串
private String getHistory(HttpServletRequest request,String id) {
//设定一个Cookie为空
Cookie history = null ;
//拿到所有的Cookie
Cookie[] cs = request.getCookies() ;
//循环判断给history赋值
for (int i = 0;cs != null && i < cs.length; i++) {
if(cs[i].getName().equals("history")){
history = cs[i] ;
break ;
}
}
//考虑情况1
if(history == null)
return id ;
//拿到客户端浏览器携带的历史记录的字符串
String value = history.getValue() ;
//考虑情况2,3
if(value.length() == 1){
if(value.equals(id))
//说明点击的是浏览过的
return id ;
else
//点击的是新的书
return id + "-" + value ;
}
//先将历史记录字符串拆分成数组,将数组中的元素放入集合中
String[] ids = value.split("-") ;
LinkedList<String> list = new LinkedList<String>(Arrays.asList(ids)) ;
int index = list.indexOf(id) ;
//考虑情况4,5,6
if(value.length() == 3){
if(index == -1){
//说明此id没有点击过
list.addFirst(id) ;
}else{
//说明点击的id以前点击过
list.remove(index) ;
list.addFirst(id) ;
}
}
//考虑情况7,8,,9,10
if(value.length() > 3){
if(index == -1){
//说明点击的id以前没有点击过
list.removeLast() ;
list.addFirst(id) ;
}else{
//说明点击的id是浏览器中已经携带的有的
list.remove(index) ;
list.addFirst(id) ;
}
}
//需要将集合中的数据形成需要的字符串
StringBuffer sb = new StringBuffer(list.get(0)) ;
for (int i = 1; i < list.size(); i++) {
sb.append("-" + list.get(i)) ;
}
return sb.toString();
}
Cookie技术详解的更多相关文章
- 《CDN技术详解》 - CDN知多少?
开发时间久了,就会接触到性能和并发方面的问题,如果说,在自己还是菜鸟的时候完全不用理会这种问题或者说有其他的高手去处理这类问题,那么,随着经验的丰富起来,自己必须要独立去处理了.或者,知道思路也行,毕 ...
- SSE技术详解:一种全新的HTML5服务器推送事件技术
前言 一般来说,Web端即时通讯技术因受限于浏览器的设计限制,一直以来实现起来并不容易,主流的Web端即时通讯方案大致有4种:传统Ajax短轮询.Comet技术.WebSocket技术.SSE(Ser ...
- 《Tomcat与Java Web开发技术详解》思维导图
越想构建上层建筑,就越觉得底层基础很重要.补课系列. 书是良心书,就是太基础了,正适合补课. [纯文字版] Tomcat与Java Web开发技术详解 Servlet Servlet的生命周期 初始化 ...
- 架构设计:远程调用服务架构设计及zookeeper技术详解(下篇)
一.下篇开头的废话 终于开写下篇了,这也是我写远程调用框架的第三篇文章,前两篇都被博客园作为[编辑推荐]的文章,很兴奋哦,嘿嘿~~~~,本人是个很臭美的人,一定得要截图为证: 今天是2014年的第一天 ...
- 「视频直播技术详解」系列之七:直播云 SDK 性能测试模型
关于直播的技术文章不少,成体系的不多.我们将用七篇文章,更系统化地介绍当下大热的视频直播各环节的关键技术,帮助视频直播创业者们更全面.深入地了解视频直播技术,更好地技术选型. 本系列文章大纲如下: ...
- 手游录屏直播技术详解 | 直播 SDK 性能优化实践
在上期<直播推流端弱网优化策略 >中,我们介绍了直播推流端是如何优化的.本期,将介绍手游直播中录屏的实现方式. 直播经过一年左右的快速发展,衍生出越来越丰富的业务形式,也覆盖越来越广的应用 ...
- Comet技术详解:基于HTTP长连接的Web端实时通信技术
前言 一般来说,Web端即时通讯技术因受限于浏览器的设计限制,一直以来实现起来并不容易,主流的Web端即时通讯方案大致有4种:传统Ajax短轮询.Comet技术.WebSocket技术.SSE(Ser ...
- Protocol Buffer技术详解(数据编码)
Protocol Buffer技术详解(数据编码) 之前已经发了三篇有关Protocol Buffer的技术博客,其中第一篇介绍了Protocol Buffer的语言规范,而后两篇则分别基于C++和J ...
- Protocol Buffer技术详解(Java实例)
Protocol Buffer技术详解(Java实例) 该篇Blog和上一篇(C++实例)基本相同,只是面向于我们团队中的Java工程师,毕竟我们项目的前端部分是基于Android开发的,而且我们研发 ...
随机推荐
- rspec学习02
元数据 RSpec-core存储元数据哈希每实例和组,其中包含他们的描述,声明的位置等等,这个hash控制很多RSpec核心的功能,包括输出格式化程序(访问描述和位置),和before,after钩子 ...
- Qt 与 JavaScript 通信
使用QWebView加载网页后,解决Qt与JavaScript通信的问题: The QtWebKit Bridge :http://qt-project.org/doc/qt-4.8/qtwebkit ...
- HDOJ/HDU 2710 Max Factor(素数快速筛选~)
Problem Description To improve the organization of his farm, Farmer John labels each of his N (1 < ...
- C++之函数指针
函数指针常用的有三类 1.指向普通函数的函数指针 2.指向类中静态成员函数的函数指针 3.指向类的成员函数的函数指针 一.指向普通函数的函数指针 #include <iostream> u ...
- Linux2.6内核--中断线被关闭的情况
中断系统是现代操作系统中不可获取的一个子系统,它由硬件主动触发并发送到CPU,最后由内核调用中断处理程序处理中断. 那么中断有时候需要关闭,这是为什么呢? 一般分为 ...
- bzoj3675: [Apio2014]序列分割
留坑 为什么别人家的斜率优化跟我一点都不一样! 为什么斜率都要变成正的... 为什么要那么推式子 为什么不能直接做啊..... 为什么不把0去掉去秒WA啊 为什么叉积去了0也过不了啊 woc啊 #in ...
- Android图片旋转,缩放,位移,倾斜,对称完整示例(一)——imageView.setImageMatrix(matrix)和Matrix
MainActivity如下: import android.os.Bundle; import android.view.MotionEvent; import android.view.View; ...
- 构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(26)-权限管理系统-分配角色给用户
原文:构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(26)-权限管理系统-分配角色给用户 构建ASP.NET MVC4+EF5+EasyUI+Unity2.x ...
- 构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(20)-权限管理系统-根据权限获取菜单
原文:构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(20)-权限管理系统-根据权限获取菜单 不知不觉到20讲,真是漫长的日子,可惜最近工作挺忙,要不可以有更多 ...
- android uri , file , string 互转
1:android Uri 介绍 http://www.cnblogs.com/lingyun1120/archive/2012/04/18/2455212.html 2:File 转成Uri < ...