cookie 的作用,就是当一个浏览器通过http 请求访问一个服务器时,这个服务器会返回key/value 键值对给客户端浏览器,在servlet 中可以这样增加cookie ,tomcat的 版本是7
public void addcookies(HttpServletResponse response,String key,String value){ Cookie cookie = new Cookie(key,value); response.addCookie(cookie); }
生成cookie 对象,将对象增加到httpServletResponse 对象中,用于返回到客户端,在tomcat 服务器中,其实就是调用response 的门面方法。org.apache.catalina.connector.ResponseFacade 的addCookie 方法
@Override public void addCookie(Cookie cookie) { //判断response 是否提交 if (isCommitted()) { return; } response.addCookie(cookie); }
将cookie 对象委托给被装饰的org.apache.catalina.connector.Response 类处理,ResponseFacade 是Responese 类的一个门面类,
public void addCookie(final Cookie cookie) { if (included || isCommitted()) { return; } // 生成符合http 协议 cookie 格式的字符串 final StringBuffer sb = generateCookieString(cookie); //将字符串放到响应头中 addHeader("Set-Cookie", sb.toString()); }
具体的生成方式
扫描二维码关注公众号,回复:
301005 查看本文章
public StringBuffer generateCookieString(final Cookie cookie) { final StringBuffer sb = new StringBuffer(); //web application code can receive a IllegalArgumentException //from the appendCookieValue invocation if (SecurityUtil.isPackageProtectionEnabled()) { AccessController.doPrivileged(new PrivilegedAction<Void>() { @Override public Void run(){ ServerCookie.appendCookieValue (sb, cookie.getVersion(), cookie.getName(), cookie.getValue(), cookie.getPath(), cookie.getDomain(), cookie.getComment(), cookie.getMaxAge(), cookie.getSecure(), cookie.isHttpOnly()); return null; } }); } else { ServerCookie.appendCookieValue (sb, cookie.getVersion(), cookie.getName(), cookie.getValue(), cookie.getPath(), cookie.getDomain(), cookie.getComment(), cookie.getMaxAge(), cookie.getSecure(), cookie.isHttpOnly()); } return sb; }
org.apache.tomcat.util.http.ServerCookie 类是处理生成cookie 的一个实体类,继承 Serializable 接口,可以序列化在网络上传输具体生成cookie 的处理逻辑
public static void appendCookieValue( StringBuffer headerBuf, int version, String name, String value, String path, String domain, String comment, int maxAge, boolean isSecure, boolean isHttpOnly) { StringBuffer buf = new StringBuffer(); // Servlet implementation checks name buf.append( name ); buf.append("="); // Servlet implementation does not check anything else /* * The spec allows some latitude on when to send the version attribute * with a Set-Cookie header. To be nice to clients, we'll make sure the * version attribute is first. That means checking the various things * that can cause us to switch to a v1 cookie first. * * Note that by checking for tokens we will also throw an exception if a * control character is encountered. */ // Start by using the version we were asked for int newVersion = version; // If it is v0, check if we need to switch if (newVersion == 0 && (!CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 && CookieSupport.isHttpToken(value) || CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 && CookieSupport.isV0Token(value))) { // HTTP token in value - need to use v1 newVersion = 1; } if (newVersion == 0 && comment != null) { // Using a comment makes it a v1 cookie newVersion = 1; } if (newVersion == 0 && (!CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 && CookieSupport.isHttpToken(path) || CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 && CookieSupport.isV0Token(path))) { // HTTP token in path - need to use v1 newVersion = 1; } if (newVersion == 0 && (!CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 && CookieSupport.isHttpToken(domain) || CookieSupport.ALLOW_HTTP_SEPARATORS_IN_V0 && CookieSupport.isV0Token(domain))) { // HTTP token in domain - need to use v1 newVersion = 1; } // Now build the cookie header // Value maybeQuote(buf, value); // Add version 1 specific information if (newVersion == 1) { // Version=1 ... required buf.append ("; Version=1"); // Comment=comment if ( comment!=null ) { buf.append ("; Comment="); maybeQuote(buf, comment); } } // Add domain information, if present if (domain!=null) { buf.append("; Domain="); maybeQuote(buf, domain); } // Max-Age=secs ... or use old "Expires" format if (maxAge >= 0) { if (newVersion > 0) { buf.append ("; Max-Age="); buf.append (maxAge); } // IE6, IE7 and possibly other browsers don't understand Max-Age. // They do understand Expires, even with V1 cookies! if (newVersion == 0 || CookieSupport.ALWAYS_ADD_EXPIRES) { // Wdy, DD-Mon-YY HH:MM:SS GMT ( Expires Netscape format ) buf.append ("; Expires="); // To expire immediately we need to set the time in past if (maxAge == 0) { buf.append( ancientDate ); } else { OLD_COOKIE_FORMAT.get().format( new Date(System.currentTimeMillis() + maxAge*1000L), buf, new FieldPosition(0)); } } } // Path=path if (path!=null) { buf.append ("; Path="); maybeQuote(buf, path); } // Secure if (isSecure) { buf.append ("; Secure"); } // HttpOnly if (isHttpOnly) { buf.append("; HttpOnly"); } headerBuf.append(buf); }
tomcat 最终构造响应头的方法在org.apache.coyote.http11.AbstractHttp11Processor 的prepareResponse中,具体片段
int size = headers.size(); for (int i = 0; i < size; i++) { getOutputBuffer().sendHeader(headers.getName(i), headers.getValue(i)); }