Cookie中存取email地址和特殊值的问题解决方法。

分类:Java, Web UI & Ajax, 服务器端技术, 程序设计, 计算机与互联网 作者: 秋天 on 24-10-2009

问题:在Cookie value中储存特殊字符并读取。

典型案例:email地址在cookie value中的存取。

解决方法:通过将Cookie value进行Base54编码后储存,读取,并解码。

环境:Java & Javascript

问题延伸:Javascript中读取Base64值错误的解决方法。

我个人认为使用email地址来作为用户帐户登录名称是一个比较不错的方法。首先email地址本身已经具备一定程度上的唯一性。通过一定的正则表达式判断或者直接使用现成的一些判断类和Service判断后可以使数据库中的该字段价值更高。其次在同一用户需要使用多个帐户的情况下,相比“用户名”来说,更加直接并且容易记忆。

使用传统的方式创建的cookie:

Cookie cookie = new Cookie(cookieName, cookieValue);
((BridgeExternalContext)context.getExternalContext()).addCookie(cookie); // icefaces中使用ExternalContext储存cookie

此时如果cookieValue的值是包含一些特定字符,比如空格,大括号,小括号,逗号,以及@等。用直接读取的方式将不能得到正确的值。

比如上面的代码中,String cookieValue = "sam@satech.com.au"

使用下面的代码直接读取:

Cookie[] cookies = ((HttpServletRequest)((BridgeExternalContext)FacesContext
	                .getCurrentInstance().getExternalContext()).getRequest()).getCookies();
for(int i=0;i<cookies.length;i++){
 if(cookies[i].getName().equals(loginCookieName)) {
 this.loginName = cookies[i].getValue();
}

你会发现,储存后在firefox的cookie查看器中能看到正常的值,而读取出来以后,值只剩下一个sam了。这显然不是我们所想要的。

最简单的解决方式,就是使用某种编码方式避开这些不能接受的字符,之后读取出来再进行解码。这里使用Base64编码来解决。其实使用任何编码方式都是可以的。

我的环境中有很多Base64类的继承类可以使用。比较常见的是

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

其他一些继承类中的加密和解码方法,可以直接作为静态方法调用,比如Icefaces自己也在utility包里面包含了。Base64类,需要的朋友可以尝试使用,原理是一样的。我这里列出使用基本的sun的misc包中的BASE64Encoder & Decoder的方法。

编码

if (log.isDebugEnabled()) {
 log.debug("Encoding string: " + this.loginName);
 }
 byte[] encodedBytes = this.loginName.getBytes(); // convert String into byte[]
 BASE64Encoder base64encoder = new BASE64Encoder(); // Create encoder
 this.base64LoginName = base64encoder.encode(encodedBytes);
 Cookie nameCookie = new Cookie(loginCookieName, this.base64LoginName);
 nameCookie.setMaxAge(SECONDS_PER_YEAR);
 nameCookie.setComment("This is the cookie to store username");
((BridgeExternalContext)context.getExternalContext()).addCookie(nameCookie); // save cookie to context

解码

Cookie[] cookies = ((HttpServletRequest)((BridgeExternalContext)FacesContext
 .getCurrentInstance().getExternalContext()).getRequest()).getCookies();
 for(int i=0;i<cookies.length;i++){
 if(cookies[i].getName().equals(loginCookieName)) {
 this.base64LoginName = cookies[i].getValue();
 BASE64Decoder decoder = new BASE64Decoder();
 try {
 byte[] decodedBytes = decoder.decodeBuffer(this.base64LoginName);
 this.loginName = new String(decodedBytes);
 } catch (IOException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 }

现在这个cookie value就能接受大部分的字符集了。但是,又发现一个问题。大部分的Base64都是以"="结尾。在纯Java环境中读取和储存都没有问题,但是某些时候会需要在Javascript中储存和读取这个值。在Javascript中读取已储存的Base64值的时候,最后面的"="会丢失,导致读取错误。

解决方案有2,第一,使用URLCodec urlCodec再次编码。第二,自己写一个判断函数来加上最后的"=" or "=="

方案一:

 public class CookieDecoder {

 private static final Log log = LogFactory.getLog(CookieDecoder.class);

 /**
 * @param cookieValue The value of the cookie to decode
 * @return Returns the decoded string
 */
 public String decode(String cookieValue) {
 if (cookieValue == null || "".equals(cookieValue)) {
 return null;
 }

 if (log.isDebugEnabled()) {
 log.debug("Decoding string: " + cookieValue);
 }
 URLCodec urlCodec = new URLCodec();
 String b64Str;
 try {
 b64Str = urlCodec.decode(cookieValue);
 }
 catch (DecoderException e) {
 log.error("Error decoding string: " + cookieValue);
 return null;
 }
 Base64 base64 = new Base64();
 byte[] encodedBytes = b64Str.getBytes();
 byte[] decodedBytes = base64.decode(encodedBytes);
 String result = new String(decodedBytes);
 if (log.isDebugEnabled()) {
 log.debug("Decoded string to: " + result);
 }
 return result;
 }
}

JS部分:

Encode:
var encodedValue = this.base64.encode(value); document.cookie = name + "=" + escape(encodedValue) + "; expires=" + this.expires.toGMTString() + "; path=" + this.path;

Decode:
var nameEQ = name + "="; var ca = document.cookie.split(';'); for(var i = 0; i < ca.length; i++) { var c = ca[i]; while (c.charAt(0)==' ') { c = c.substring(1,c.length); } if (c.indexOf(nameEQ) == 0) { var encodedValue = c.substring(nameEQ.length,c.length); return this.base64.decode(unescape(encodedValue)); } } return null;

方案二:padString()来解决最后那个等号。

 private static final Log log = LogFactory.getLog(CookieDecoder.class);

/**
 * @param cookieValue The value of the cookie to decode
 * @return Returns the decoded string
 */
public String decode(String cookieValue) {
 if (cookieValue == null || "".equals(cookieValue)) {
 return null;
 }

 if (!cookieValue.endsWith("=")) {
 cookieValue = padString(cookieValue);
 }

 if (log.isDebugEnabled()) {
 log.debug("Decoding string: " + cookieValue);
 }

 Base64 base64 = new Base64();
 byte[] encodedBytes = cookieValue.getBytes();
 byte[] decodedBytes = base64.decode(encodedBytes);
 String result = new String(decodedBytes);
 if (log.isDebugEnabled()) {
 log.debug("Decoded string to: " + result);
 }
 return result;
}

private String padString(String value) {
 int mod = value.length() % 4;
 if (mod <= 0) {
 return value;
 }
 int numEqs = 4 - mod;
 if (log.isDebugEnabled()) {
 log.debug("Padding value with " + numEqs + " = signs");
 }
 for (int i = 0; i < numEqs; i++) {
 value += "=";
 }
 return value;
}

JS部分:现在在JS中就可以按照正常方法读取了

 var encodedValue = this.base64.encode(value);
document.cookie = name + "=" + encodedValue +
 "; expires=" + this.expires.toGMTString() +
 "; path=" + this.path;

至此,基本解决问题。

Javascript resize font-size em FF IE

分类:Web UI & Ajax, 网页&平面设计 作者: 秋天 on 08-04-2009

标签分类 : , , , ,

通过JS来控制网页字体,全局用em定制。就能在网页需要的地方,明显位置放置一个字体大小控制按钮。能增长的地方用em控制,定大的地方用pt or px。

据说现在主流浏览器都已经支持全局缩放 (具体看这里),就是放大整个screen而不仅仅是字体,但是由于还是需要照顾那30%的IE6 或者低版本Safari Opera用户,所以仍然需要用到。并且,具体用JS如何实现全屏缩放,暂时没找到实现方案。

在em设计的具体运用中,IE7 和 FF在自身缩放上又会有一些个bug,后文有引用别人的描述和解决方案。

clagnut.com 这家伙说的:

Text for the screen is sized with CSS in terms of pixels, ems or keywords. As most of us know, sizing with pixels is easy: get your selector and give it a font-size – no more thought required. Sizing with keywords is more complicated and requires a few workarounds, but you’re in luck as the techniques are well documented. That leaves ems. At this point people often leg it. ‘Ems are too inconsistent,’ they say, ‘they’re too hard; they never work.’ Well that may be the received wisdom, but if ever the was a case of FUD then this is it. I will now attempt to show you how ems can be as quick and easy to use as pixels. 点击浏览文章的全部内容 »


如果你也有Blog,欢迎申请链接加入我的朋友圈