測試環境搭建
使用Springboot構建web server, 在測試方法中打印接收的cookie。
@RestController
@RequestMapping("/register/test/service")
public class TestService {
private Log logger = LogFactory.getLog(TestService.class);
// 使用HttpServletRequest 獲取cookie
@RequestMapping(value = "/ping", method = RequestMethod.GET)
public Response ping(HttpServletRequest httpRequest, HttpServletResponse httpServletResponse) throws IOException {
Cookie[] cookies = httpRequest.getCookies();
logger.info("cookies info"+JsonUtils.toJson(cookies));
//Mice
return new Response().setData("OK!!!");
}
}
Postman開起Interceptor,在如下圖所示
輸URL: http://localhost:8080/register/test/service/ping
Header:Cookie:test=hello(name= test, value=hello的cookie)
測試結果
返回cookie, Cookie在使用期限內,一值存在,在服務器端可以修改cookie的生命周期
Cookie的幾點常識
//文本數據明文,登陸分配,用於后台校驗識別不同的用戶
簡單地說,cookie就是瀏覽器儲存在用戶電腦上的一小段文本文件。cookie 是純文本格式,不包含任何可執行的代碼。一個web頁面或服務器告知瀏覽器按照一定規范來儲存這些信息,並在隨后的請求中將這些信息發送至服務器,Web服務器就可以使用這些信息來識別不同的用戶。大多數需要登錄的網站在用戶驗證成功之后都會設置一個cookie,只要這個 cookie 存在並可以,用戶就可以自由瀏覽這個網站的任意頁面。再次說明,cookie 只包含數據,就其本身而言並不有害。
//區分訪問web服務器的來源,維護狀態
為什么需要Cookie?
因為HTTP協議是無狀態的,對於一個瀏覽器發出的多次請求,WEB服務器無法區分是不是來源於同一個瀏覽器。所以,需要額外的數據用於維護會話。 Cookie 正是這樣的一段隨HTTP請求一起被傳遞的額外數據。
//存儲大小受限
Cookie 的限制。 大多數瀏覽器支持最大為 4096 字節的 Cookie。由於這限制了 Cookie 的大小,最好用 Cookie 來存儲少量數據,或者存儲用戶 ID 之類的標識符。用戶 ID 隨后便可用於標識用戶,以及從數據庫或其他數據源中讀取用戶信息。 瀏覽器還限制站點可以在用戶計算機上存儲的 Cookie 的數量。大多數瀏覽器只允許每個站點存儲 20 個 Cookie;如果試圖存儲更多 Cookie,則最舊的 Cookie 便會被丟棄。有些瀏覽器還會對它們將接受的來自所有站點的 Cookie 總數作出絕對限制,通常為 300 個。
詳細描述見下文
http://bubkoo.com/2014/04/21/http-cookies-explained/
Java Spring Read Cookie
使用CookieVlaue標簽來獲取指定name的Cookie
// 使用HttpServletRequest 獲取cookie
@RequestMapping(value = "/ping", method = RequestMethod.GET)
public Response ping(@CookieValue("test") String fooCookie) throws IOException {
//Mice
return new Response().setData("OK, cookieValue=!!!" + fooCookie);
}
在上面的的代碼中如果CooKie不存在,會拋出返回異常:
{
"timestamp": 1466584427218,
"status": 400,
"error": "Bad Request",
"exception": "org.springframework.web.bind.ServletRequestBindingException",
"message": "Missing cookie 'majun' for method parameter of type String",
"path": "/register/test/service/ping"
}
可以通過設置默認值來解決這個異常,如果業務上不呈現這個異常的話!!
使用HttpServletRequest可以獲取Cookie列表
Java Spring Create Cookie
使用HttpServletResponse, Cookie類,
// 使用HttpServletResponse增加cookie, cookie會返回給前端
@RequestMapping(value = "/getCookie", method = RequestMethod.GET)
public Response getCookie(HttpServletResponse httpServletResponse) throws IOException {
Cookie cookie = new Cookie("majun", "xiaoya");
cookie.setMaxAge(10); //設置cookie的過期時間是10s
httpServletResponse.addCookie();
return new Response().setData("allocate cookie success!!!");
}
如果創建的Cookie (name相同)已經存在,那么新的Cookie會覆蓋老的cookie。
可以在Postman看到Cookie的返回信息
攔截器和Cookie
**攔截器是什么? **
攔截器的作用在於對處理器進行預處理和后處理,類似於filter。攔截器的原理詳見:
http://www.cnblogs.com/fangjian0423/p/springmvc-interceptor.html
攔截器的使用場景
1、日志記錄:記錄請求信息的日志,以便進行信息監控、信息統計、計算PV(Page View)等。
2、權限檢查:如登錄檢測,進入處理器檢測檢測是否登錄,如果沒有直接返回到登錄頁面;
3、性能監控:有時候系統在某段時間莫名其妙的慢,可以通過攔截器在進入處理器之前記錄開始時間,在處理完后記錄結束時間,從而得到該請求的處理時間(如果有反向代理,如apache可以自動記錄);
4、通用行為:讀取cookie得到用戶信息並將用戶對象放入請求,從而方便后續流程使用,還有如提取Locale、Theme信息等,只要是多個處理器都需要的即可使用攔截器實現。
5、OpenSessionInView:如Hibernate,在進入處理器打開Session,在完成后關閉Session。
…………本質也是AOP(面向切面編程),也就是說符合橫切關注點的所有功能都可以放入攔截器實現。
Springboot實現攔截器
定義攔截面類
package com.im.server.Interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Created by majun on 16/6/22.
*/
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
System.out.println(">>>MyInterceptor>>>>>>>在請求處理之前進行調用(Controller方法調用之前)");
Cookie[] cookies = httpServletRequest.getCookies();
if (cookies == null || cookies.length == 0) {
throw new Exception("illegal Login");
}
try {
for (Cookie cookie : cookies) {
if (cookie.getName().equals("USER_TOKEN")) {
//User user =
httpServletRequest.setAttribute("USER_TOKEN", "{name: GUHUA, age: 20}");
return true;
}
}
throw new Exception("illegal Login");
} catch (Exception exp) {
throw exp;
}
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println(">>>MyInterceptor>>>>>>>請求處理之后進行調用,但是在視圖被渲染之前(Controller方法調用之后)");
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println(">>>MyInterceptor>>>>>>>在整個請求結束之后被調用,也就是在DispatcherServlet 渲染了對應的視圖之后執行(主要是用於進行資源清理工作)");
}
}
配置攔截器:繼承WebMvcConfigurerAdapter類即可
package com.im.server.conf;
import com.im.server.Interceptor.MyInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
public class MyWebAppConfigurer extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/register/test/service/**");
super.addInterceptors(registry);
}
}
控制器中獲取USER_TOKEN對應的用戶內容
// 使用HttpServletResponse增加cookie, cookie會返回給前端
@RequestMapping(value = "/getUserInfo", method = RequestMethod.GET)
public Response getUser(HttpServletRequest httpServletRequest) throws IOException {
Object user_token = httpServletRequest.getAttribute("USER_TOKEN");
return new Response().setData(user_token);
}
測試結果
下面的鏈接詳細講了Spring mvc攔截器的實現原理:
http://www.cnblogs.com/fangjian0423/p/springmvc-interceptor.html