場景:調用接口完成某項操作,但是接口是強登錄的,需要cookie, 且cookie會過期;服務器會限制登錄的次數,如果一個賬號頻繁登錄,則在短時間內無法正常登錄,因此無法做到每調用接口一次就登錄一次,且這樣的效率也會比較低;
方法: 采用httpClient獲取cookie, 並在接口上加入cookie校驗;
核心代碼:
0. 需要加入的jar包
1 import org.apache.commons.lang.StringUtils; 2 import org.apache.commons.httpclient.HttpClient; 3 import org.apache.commons.httpclient.methods.GetMethod; 4 import org.apache.http.Header; 5 import org.apache.http.HttpResponse; 6 import org.apache.http.HttpStatus; 7 import org.apache.http.StatusLine; 8 import org.apache.http.client.CookieStore; 9 10 import org.apache.http.client.HttpClient; 11 import org.apache.http.client.methods.HttpGet; 12 import org.apache.commons.httpclient.methods.GetMethod; 13 14 import org.apache.http.client.methods.HttpPost; 15 16 import org.apache.http.cookie.Cookie; 17 import org.apache.http.impl.client.BasicCookieStore; 18 19 import org.apache.http.impl.client.HttpClients; 20 import org.apache.http.protocol.BasicHttpContext; 21 import org.apache.http.protocol.HttpContext;
需要導入pom.xml文件的依賴
1 <dependency> 2 <groupId>org.apache.httpcomponents</groupId> 3 <artifactId>httpclient</artifactId> 4 <version>4.5.5</version> 5 </dependency> 6 <dependency> 7 <groupId>commons-httpclient</groupId> 8 <artifactId>commons-httpclient</artifactId> 9 <version>3.1</version> 10 </dependency>
1. 獲取cookie, 其中
getUrl(loginUrl, username, password); 是將url進行拼接,loginUrl 加上登陸需要的參數拼接為一個請求, 其中loginUrl就是登錄url
public String getCookies(String username, String password){ CookieStore cookieStore = new BasicCookieStore(); HttpContext localContext = new BasicHttpContext(); localContext.setAttribute(COOKIE_STORE, cookieStore); HttpClient client = HttpClients.createDefault(); String authUrl = getUrl(loginUrl, username, password); System.out.println("authUrl = " + authUrl); HttpPost post = new HttpPost(authUrl); try { response = client.execute(post, localContext); StatusLine statusLine = response.getStatusLine(); int statusCode = statusLine.getStatusCode(); System.out.println("first execute code :" + statusCode); if(statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY){ Header firsRedirectHeader = response.getFirstHeader("location"); String firstRedirectUrl = firsRedirectHeader.getValue(); HttpGet get = new HttpGet(firstRedirectUrl); HttpResponse getResponse = client.execute(get, localContext); StatusLine statusLine2 = getResponse.getStatusLine(); int statusCode2 = statusLine2.getStatusCode(); System.out.println("second execute code :" + statusCode2); System.out.println("cookie :" + cookieStore.getCookies()); List<Cookie> cookieList = cookieStore.getCookies(); StringBuffer tmpCookie = new StringBuffer(); for(int i = 0 ; i < cookieList.size(); i++) { tmpCookie.append(cookieList.get(i).getName()).append("="); tmpCookie.append(cookieList.get(i).getValue()).append(";"); tmpCookie.append("domain=").append(cookieList.get(i).getDomain()).append(";"); tmpCookie.append("path=").append(cookieList.get(i).getPath()).append(";"); } get.releaseConnection(); return tmpCookie.toString(); } } catch (IOException e) { e.printStackTrace(); }finally { if(post != null){ post.releaseConnection(); } } return "-1"; }
// formData 里面需要填充的內容根據瀏覽器f12調試模式中,獲取到請求的信息
private String getUrl(String url, String username, String password){ if(StringUtils.isEmpty(url)){ System.out.println("url is empty"); return "-1"; } formData = new HashMap<String, String>(); formData.put("username", username); formData.put("password", password); formData.put("app", "web"); formData.put("product", "xxx");//產品根據實際情況定 formData.put("tp", "urstoken"); formData.put("cf", "7"); formData.put("fr", "1"); formData.put("ru", "https://xxxxxxxn"); //鏈接可以根據自己在瀏覽器的信息中拿到,不同的登錄該部分地址是不一樣的 formData.put("er", "https://xxxxx"); String arguments = MaptoUrl(formData); return url + arguments; }
public String MaptoUrl(Map<String, String> map){
String arguments="?";
Iterator iterator = map.entrySet().iterator();
Boolean first_args = true;
while(iterator.hasNext()){
Map.Entry entry = (Map.Entry) iterator.next();
Object key = entry.getKey();
Object val = entry.getValue();
String key_str = (String) key;
String val_str = (String) val;
if(first_args == false){
arguments = arguments + "&";
}
first_args = false;
arguments = arguments + key_str;
arguments = arguments + "=";
arguments = arguments + val_str;
}
return arguments;
}
2. 獲取到有效的cookie, 因為第一步獲取到cookie后,cookie在一段時間內可能會失效,因此為了后面接口中帶入有效的cookie, 這里還需要該函數來獲取真正有效的cookie;
public String getValidCookie(String cookie){ if(cookie.contains("DICT_SESS")){ return cookie; }else{ Login login = new Login(); String validCookie = login.getCookies(username, password); return validCookie; } }
3. 真正執行接口的代碼, for循環2次,第一次是去請求接口,如果接口返回的結果是403權限被拒絕,則需要調用login.getValidCookie()方法登錄一次,獲取真正的cookie.,然后進行第二次接口請求;
如果接口返回的結果是0, 則表示cookie依然有效,則直接返回true; 其中參數url是需要真正請求的接口;
1 public Boolean executeMethod(String url) { 2 String result = "-1"; 3 for(int i = 0; i < 2; i++) { 4 GetMethod getMethod = new GetMethod(url); 5 getMethod.setRequestHeader("cookie", cookie); 6 try { 7 httpClient.executeMethod(getMethod); 8 System.out.println("method result = " + getMethod.getResponseBodyAsString()); 9 result = getMethod.getResponseBodyAsString(); 10 } catch (IOException e) { 11 e.printStackTrace(); 12 } 13 JSONObject obj = JSONObject.parseObject(result); 14 if ("0".equals(obj.get("err").toString())) { 15 return true; 16 }else if ("403".equals(obj.get("err").toString())) { 17 cookie = login.getValidCookie(cookie); 18 continue; 19 }else{ 20 return false; 21 } 22 } 23 return false; 24 25 }
4. 在類加載的時候先登錄一次,保存cookie,且是全局變量;則在第3步更新cookie的時候,就可以更新該變量;
1 Login login = new Login();
2 private String cookie = login.getCookies(username, password);
3 HttpClient httpClient = new HttpClient();
public static void main(String[] args) {
Login httpclientDemo = new Login();
org.apache.commons.httpclient.HttpClient httpClient = new org.apache.commons.httpclient.HttpClient();
String cookie = httpclientDemo.getCookies("username", "password");
System.out.println("final cookie = " + cookie);
String url = yyyyy";//需要請求的url
GetMethod getMethod = new GetMethod(url);
getMethod.setRequestHeader("cookie", cookie);
try {
httpClient.executeMethod(getMethod);
System.out.println("method result = " + getMethod.getResponseBodyAsString());
} catch (IOException e) {
e.printStackTrace();
}
}
總結: 第三步判斷cookie失效重新請求的實現方法有點不太好,希望大家多多交流;
