HttpURLConnection之Cookie传递
摘要:本文主要介绍使用HttpURLConnection访问Miracle系统Cookie传递相关技术要点
关键词:HttpURLConnection;CookieHandler;Session; Cookie;
- 简介
我们知道HTTP协议是一种无状态协议,基于TCP/IP,即客户端请求服务器,服务器处理后,进行响应,这个过程是无状态的。
但是在有些时候需要保存一些客户端的请求信息,用以识别客户端的某些状态,有针对性的去保持某些客户端的习惯。这些时候,就需要去记录客户端的连接状态,识别请求的状态等。所以为了解决类似的事情,就需要使用到了 Cookie 和 Session。
以Miracle程序为例,使用Cookie的场景:记住用户名、记住密码的功能,当勾选这个的时候,下次进入该网站时,就会自动设置登录名或自动登录;使用Seesion的场景:利用Seesion来验证用户是否已登录。
一般情况,使用浏览器作为客户端,访问Web程序,开发员无需过多关注Session和Cookie。但如果把客户端替换成HttpClient、HttpURLConnection或移动APP等其他应用程序,这就涉及到手工处理Cookie的问题。
本文以HttpURLConnection为例,介绍如何实现Cookie的传递、接收。
- HttpURLConnection介绍
HttpURLConnection提供了访问HTTP资源的一种方式,是Java的标准类,它继承自URLConnection,可用于向指定网站发送请求。它在URLConnection的基础上提供了如下便捷的方法:
int getResponseCode(); // 获取服务器的响应代码。 String getResponseMessage(); // 获取服务器的响应消息。 String getResponseMethod(); // 获取发送请求的方法。 void setRequestMethod(String method); // 设置发送请求的方法。 |
使用HttpURLConnection访问HTTP资源一般范围如下六步:
1.使用java.net.URL封装个的HTTP资源url,并使用openConnection方法获得HttpURLConnection对象,代码如下:
URL url = new URL(targetUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); |
2.设置请求方法,例如GET、POST等,代码如下:
String method = "GET"; conn.setRequestMethod(method); |
3.设置输入输出及其他权限。代码如下:
conn.setUseCaches(false); conn.setDoOutput(true); conn.setDoInput(true); |
4.设置HTTP请求头。代码如下:
conn.setRequestProperty("Accept", "application/json, text/javascript"); conn.setRequestProperty("User-Agent", "Mozilla/5.0"); conn.setRequestProperty("Content-Type", "text/json;charset=UTF-8"); conn.setRequestProperty("Cache-Control", "no-cache"); |
5.输入输出数据。代码如下:
InputStream in = conn.getInputStream(); OutputStream out = conn.getOutputStream(); |
6.关闭输入和输出流。代码如下:
in.close(); out.close(); |
- CookieHander的使用
作为HTTP协议处理器的一部分,J2SE5.0增加了CookieHandler来,用以管理Cookie。通过如下方式注册:
CookieManager cookieManager = new CookieManager(); CookieHandler.setDefault(cookieManager); |
注册完成后,发起HttpURLConnection连接,服务器端响应的Cookie信息就会保存到CookieManager中。响应完成后,可以通过如下方式获取Cookie:
CookieStore cookieStore = cookieManager.getCookieStore(); URI uri = getConnectUri(conn); List<HttpCookie> httpCookies = cookieStore.get(uri); |
再次发起请求时,CookieHander会自动携带浏览器返回的Cookie信息,对于客户端设置的Cookie信息,如主题风格theme-skin,需要发起请求的时候,使用如下方式携带:
conn.setRequestProperty("Cookie", "theme-skin=metro-dark;"); |
- 本地Cookie更新
HttpURLConnection响应完成后,服务端可能会删除某些Cookie。如退出登录后,会删除记住登录用户相关的Cookie。此时需更新本地Cookie信息,需要分两步。
第一步 ,将cookieManager中的Cookie更新或新增到本地。
CookieStore cookieStore = cookieManager.getCookieStore(); URI uri = getConnectUri(conn); List<HttpCookie> httpCookies = cookieStore.get(uri);
// 将cookieStore中的cookie更新到浏览器 for (HttpCookie httpCookie : httpCookies) { String name = httpCookie.getName(); if (KEY_JSESSIONID.equals(name)) continue;
String value = httpCookie.getValue(); // 查询浏览器中的Cookie Cookie cookie = getCookie(request, name); // Cookie不存在,则新增 if (cookie == null) { Cookie newCookie = new Cookie(name, value); newCookie.setPath(cookiePath); response.addCookie(newCookie); } // Cookie存在,则更新 else { cookie.setValue(httpCookie.getValue()); } } |
第二步,删除本地多余的Cookie
Cookie[] cookies = request.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { String name = cookie.getName(); // 本地处理的Cookie过滤掉 if ("login_remember_name".equals(name)) continue; if ("lang".equals(name)) continue;
HttpCookie httpCookie = getHttpCookie(httpCookies, name); if (httpCookie == null || httpCookie.getMaxAge() == 0) { cancelCookie(request, response, name); } } } |
删除本地Cookie(以浏览器为例)的方法如下:
void cancelCookie(HttpServletRequest request, HttpServletResponse response, String cookieName) { Cookie cookie = new Cookie(cookieName, null); cookie.setMaxAge(0); cookie.setPath(getCookiePath(request)); response.addCookie(cookie); }
String getCookiePath(HttpServletRequest request) { String contextPath = request.getContextPath(); return contextPath.length() > 0 ? contextPath : "/"; } |
至此,HttpURLConnection使用CookieHander进行Cookie传输与更新的技术要点已经总结完毕。
- 总结
通过使用过CookieHander进行Cookie传输,我们完全可以通过Java模拟类似Nginx反向代理,浏览器请求代理服务器,代理服务器做好Cookie传输,对应响应内容,根据实际业务需要定制处理。