概念
会话
用户进入网站,开始浏览信息到关闭浏览器的过程,就称之为是一次会话,浏览器和服务器之间在进行多次请求间共享数据的过程,就称为会话跟踪技术,每一个 HTTP 请求都会在请求头中携带 cookie 到服务端
无状态协议
由于http协议是无状态的,当一个客户端向服务器端发出请求,然后Web服务器返回响应后该连接就被关闭了,在服务器端不保留连接的有关信息,因此可采用在浏览器中cookie缓存服务端数据或者一些特殊资源数据。当浏览器从服务器上请求 web 页面时, 属于该页面的 cookie 会被添加到该Request请求中。服务端通过request来获取用户的信息,其中Cookie 以名/值对形式存储
cookie
cookie是一种保存在客户端的用户数据文件,也是一种会话跟踪技术,每一个 HTTP 请求和响应都会携带 cookie,cookie 是不需要我们手动设置,就会自动在客户端和服务端之间游走的数据,我们只是需要设置 cookie 的内容(前端/后端均可设置),cookie 是以字符串的形式存储,在字符串中以 key=value 的形式出现,每一个 key=value 是一条数据,多个数据之间以;分割
cookie选项详解
每个cookie都有一定的属性,如什么时候失效,要发送到哪个域名,哪个路径等等。cookie选项包括:expires、domain、path、secure、HttpOnly等
expires设置“cookie 什么时间内有效”。expires其实是cookie失效日期,expires必须是 GMT 格式的时间(可以通过new Date().toGMTString()或者 new Date().toUTCString() 来获得)
domain是域名,path是路径,两者加起来就构成了 URL,domain和path一起来限制 cookie 能被哪些 URL 访问。例如某cookie的 domain为“baidu.com”, path为“/ ”,若请求的URL(URL 可以是js/html/img/css资源请求,但不包括 XHR 请求)的域名是“baidu.com”或其子域如“api.baidu.com”、“dev.api.baidu.com”,且 URL 的路径是“/ ”或子路径“/home”、“/home/login”,则浏览器会将此 cookie 添加到该请求的 cookie 头部中。所以domain和path2个选项共同决定了cookie何时被浏览器自动添加到请求头部中发送出去。如果没有设置这两个选项,则会使用默认值。domain的默认值为设置该cookie的网页所在的域名,path默认值为设置该cookie的网页所在的目录。
secure选项用来设置cookie只在确保安全的请求中才会发送。当请求是HTTPS或者其他安全协议时,包含 secure 选项的 cookie才能被发送至服务器。默认情况下,cookie不会带secure选项(即为空)。所以默认情况下,不管是HTTPS协议还是HTTP协议的请求,cookie 都会被发送至服务端。但要注意一点,secure选项只是限定了在安全情况下才可以传输给服务端,但并不代表你不能看到这个 cookie。
httponly选项用来设置cookie是否能通过 js 去访问。默认情况下,cookie不会带httpOnly选项(即为空),所以默认情况下,客户端是可以通过js代码去访问(包括读取、修改、删除等)这个cookie的。当cookie带httpOnly选项时,客户端则无法通过js代码去访问(包括读取、修改、删除等)这个cookie。在客户端是不能通过js代码去设置一个httpOnly类型的cookie的,这种类型的cookie只能通过服务端来设置
cookie特点
- 每个域名下cookie大小一般是 4 KB 左右
- 每个域名下数量有限制,一般是 50 条左右
- 有时效性,也就是有过期时间,一般是 会话级别(也就是浏览器关闭就过期了)
- 有域名限制,在哪个域名下存储的cookie,只能在哪个域名下访问
cookie应用场景
- 会话状态管理(如用户登录状态、购物车等)
- 个性化设置(保存用户设置的样式,以及国际化语言类型值等)
- 浏览器行为跟踪(如跟踪分析用户行为等)
cookie的缺点
- cookie可能被禁用
- cookie安全性不够高
- cookie存储空间很小(只有4KB左右)
- cookie操作麻烦,没有方便的API
前台获取设置cookie示例
//JavaScript来创建 、读取、及删除 cookie。
//其中可添加过期时间expires; path指出浏览器cookie 的路径。默认情况下,cookie 属于当前页面/
document.cookie="username=John Doe; expires=Thu, 18 Dec 2043 12:00:00 GMT; path=/";
//JavaScript读取cookie
//其中document.cookie 将以字符串的方式返回所有的 cookie,类型格式: cookie1=value; cookie2=value; cookie3=value;
var x = document.cookie;
cookie实战
前台language.js中设置/获取国际化语言值的方法
var getCookie = function(name, value, options) {
if (typeof value != 'undefined') { // name and value given, set cookie
options = options || {};
if (value === null) {
value = '';
options.expires = -1;
}
var expires = '';
if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
var date;
if (typeof options.expires == 'number') {
date = new Date();
date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
} else {
date = options.expires;
}
expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
}
var path = options.path ? '; path=' + options.path : '';
var domain = options.domain ? '; domain=' + options.domain : '';
var s = [cookie, expires, path, domain, secure].join('');
var secure = options.secure ? '; secure' : '';
var c = [name, '=', encodeURIComponent(value)].join('');
var cookie = [c, expires, path, domain, secure].join('');
document.cookie = cookie;
} else { // only name given, get cookie
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
};
//设置语言为中文简体 zh-CN
getCookie("_lang_","zh-CN",{
expires: 30,
path:''
});
//获取cookie中名字为_lang_对应的值
getCookie("_lang_")
扩展
国际化解决方案-非前后端分离模式
一.传统的jquery前端页面解决方案
jquery-i18前端页面国际化执行流程
1.首先需要引入jquery.js,jquery.i18n.properties.js,并且i18n放在jquery.js后面引入,并加入自定义的language.js代码
2.resource/static/assets/i18n创建不同语言文件,包括messages_zh_CN.properties/messages_zh_TW.properties/messages_en.properties等
3.在html页面中设置标签的class=i18n,data-properties="xxx" data-ptype="xxx",
首先language.js会加载对应的语言文件
然后根据页面对应的data-ptype找到data-properties
最后利用jquery.i18n.properties.js的$.i18n.prop进行赋值,示例如下:
<!--html-->
<div class="i18n" data-properties="htmlmsg" data-ptype="html"></div>
<!--text-->
<div class="i18n" data-properties="hellomsg1" data-ptype="text"></div>
二.后端处理国际化
1. 新增语言拦截器localeChangeInterceptor,通过它来获取前台传递过来的语言参数
具体实现流程:
a. 自定义的LocaleConfig 配置类中自定义@Bean LocaleChangeInterceptor(配置类+@Bean就是一种:把bean加载到ioc容器的一种机制,并且覆盖底层的配置类)
b. LocaleChangeInterceptor通过它的子类CustomLocaleChangeInterceptor的preHandle方法来获取语言参数
-- preHandle方法获取语言参数逻辑
首先从request获取默认'DEFAULT_PARAM_NAME = "locale"'值,若为空,则从headerName中取值,
若headerName也为空,则从cookies取值。
-- 获取到newLocale语言值后,使用LocaleResolver进行解析,其中LocaleResolver是LocaleConfig配置类自定义的bean,其中若无法解析,则默认设置为zh-CN
c. 编写获取语言资源服务LocaleMessageService,提供获取资源对应字段值、资源所有值等方法
--其中 注入到LocaleMessageService的messageSource是LocaleConfig配置类自定义的bean,并通过其子类ExposedResourceBundleMessageSource初始设置了语言资源路径以及编码,并提供获取资源key等方法
d. WebMvcConfig 添加语言拦截器,绑定LocaleConfig 配置类中自定LocaleChangeInterceptor
实际应用
e. Controller控制层调用LocaleMessageService提供的功能返回对应语言所需的资源信息
f. ExceptionHandlerAspect类以面向切面的方式统一处理项目中异常错误信息的国际化