如何使用 Retrofit/OkHttpClient 从响应中获得多个 Set-Cookie header?
How to get more than one Set-Cookie header from response using Retrofit/OkHttpClient?
我正尝试在 Android 上使用 Retrofit/OkHttpClient 进行身份验证调用。服务器用两个 Set-Cookie header 响应 302 并且 okHttp 处理重定向。我找到了一些使用 cookieManager 获取这些 cookie 的技巧。但是 cookieManager 似乎只读取一个 Set-Cookie header.
我在服务器响应中有这个 headers:
Set-Cookie:first=1
Set-Cookie:second=2
这是我的 cookieManager 部分:
private static CookieManager cookieManager;
(...)
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setFollowSslRedirects(true);
okHttpClient.setAuthenticator(new NTLMAuthenticator(user, passwd, domain));
cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
okHttpClient.setCookieHandler(cookieManager);
并处理Set-Cookie headers:
public void checkForSetCookies() {
List<retrofit.client.Header> headerList = new ArrayList<>();
List <HttpCookie> cookies = cookieManager.getCookieStore().getCookies();
//List cookies has only one cookie: first=1
for (HttpCookie cookie : cookies) {
retrofit.client.Header header = new retrofit.client.Header("Set-Cookie", cookie.toString());
headerList.add(header);
}
if (headerList.size() > 0) {
Commons.setLoginRetofitCookies(headerList);
}
}
有没有办法强制 cookieManager 读取我的两个 Set-Cookie header?
在此先感谢您的帮助。
我想我解决了问题。 CookieManager class 正在解析响应 headers 以列出:
List<HttpCookie> cookies = parseCookie(responseHeaders);
因此第二个 cookie 被覆盖。
我决定在 class 内部创建 MyCookieManager 并覆盖其 put 方法以将 cookie 值放入字符串列表。我调用 super 方法来完成所有 headers 验证。
class MyCookieManager extends CookieManager {
@Override
public void put(URI uri, Map<String, List<String>> stringListMap) throws IOException {
super.put(uri, stringListMap);
if (stringListMap != null && stringListMap.get("Set-Cookie") != null)
for (String cookieValue: stringListMap.get("Set-Cookie")) {
cookiesStrings.add(cookieValue);
}
}
}
现在一切正常:)
要从响应中获取多个 "Set-Cookie" header :
Call<LoginResponse> call = apiService.login(loginRequest);
call.enqueue(new Callback<LoginResponse>() {
@Override
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
showProgress(false);
if (response.body() != null) {
LoginResponse loginResponse = response.body();
//Get headers from response
Headers headerResponse = response.headers();
//convert header to Map
Map<String, List<String>> headerMapList = headerResponse.toMultimap();
//Get List of "Set-Cookie" from Map
List<String> allCookies = headerMapList.get("Set-Cookie");
String cookieval = "";
for (int i = 1; i < allCookies.size(); i++) {
allCookies.get(i);
//concat all cookies in cookieval.
cookieval = cookieval + allCookies.get(i);
}
//Save cookies value in Application class.
((AppConfig) getApplication()).setCookies(cookieval);
((AppConfig) getApplication()).setUserInfo(loginResponse);
if (loginResponse.getStatus().equals("ok")) {
startActivity(new Intent(LoginActivity.this, MainActivity.class));
mAuthTask = true;
finish();
} else {
mPasswordView.setError(getString(R.string.error_incorrect_password));
mPasswordView.requestFocus();
}
}
}
@Override
public void onFailure(Call<LoginResponse> call, Throwable t) {
Log.d(TAG, "onFailure: ");
mAuthTask = false;
}
});
传递其他服务中的所有 cookie(例如注销服务)
@Headers({"Content-Type: application/json"})
@POST("request/get/user/logout")
Call<LogoutResponse> logout(@Header("Cookie") String cookie);
在Api界面添加这段代码
现在像这样调用注销服务:
Call<LogoutResponse> call = apiService.logout(((AppConfig) getApplication()).getCookies());
call.enqueue(new Callback<LogoutResponse>() {
@Override
public void onResponse(Call<LogoutResponse> call, Response<LogoutResponse> response) {
if(response.body() != null){
LogoutResponse logoutResponse = response.body();
if (logoutResponse.getStatus().equals("ok")) {
finish();
startActivity(new Intent(MainActivity.this, LoginActivity.class));
}
}
}
@Override
public void onFailure(Call<LogoutResponse> call, Throwable t) {
Log.d(TAG, "onFailure: ");
}
});
您可以使用 Kotlin 编写扩展函数。
fun Headers.getCookies(): String? {
var cookieString: String? = null
this.toMultimap()["Set-Cookie"]?.forEach {
cookieString += it
}
return cookieString
}
您可以使用 response.headers().values("some_header")
获取 header
的多个值
val authCookies = mutableMapOf<String, String>()
val response = restManager.login(AuthDto().apply {
clientId = agent.clientId
apiKey = "awesome_api_key"
}).execute()
response.headers().values("Set-Cookie").forEach {
if (it.startsWith("auth=")) {
authCookies["auth"] = it
} else {
authCookies["refresh"] = it
}
}
我正尝试在 Android 上使用 Retrofit/OkHttpClient 进行身份验证调用。服务器用两个 Set-Cookie header 响应 302 并且 okHttp 处理重定向。我找到了一些使用 cookieManager 获取这些 cookie 的技巧。但是 cookieManager 似乎只读取一个 Set-Cookie header.
我在服务器响应中有这个 headers:
Set-Cookie:first=1
Set-Cookie:second=2
这是我的 cookieManager 部分:
private static CookieManager cookieManager;
(...)
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setFollowSslRedirects(true);
okHttpClient.setAuthenticator(new NTLMAuthenticator(user, passwd, domain));
cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ALL);
okHttpClient.setCookieHandler(cookieManager);
并处理Set-Cookie headers:
public void checkForSetCookies() {
List<retrofit.client.Header> headerList = new ArrayList<>();
List <HttpCookie> cookies = cookieManager.getCookieStore().getCookies();
//List cookies has only one cookie: first=1
for (HttpCookie cookie : cookies) {
retrofit.client.Header header = new retrofit.client.Header("Set-Cookie", cookie.toString());
headerList.add(header);
}
if (headerList.size() > 0) {
Commons.setLoginRetofitCookies(headerList);
}
}
有没有办法强制 cookieManager 读取我的两个 Set-Cookie header?
在此先感谢您的帮助。
我想我解决了问题。 CookieManager class 正在解析响应 headers 以列出:
List<HttpCookie> cookies = parseCookie(responseHeaders);
因此第二个 cookie 被覆盖。
我决定在 class 内部创建 MyCookieManager 并覆盖其 put 方法以将 cookie 值放入字符串列表。我调用 super 方法来完成所有 headers 验证。
class MyCookieManager extends CookieManager {
@Override
public void put(URI uri, Map<String, List<String>> stringListMap) throws IOException {
super.put(uri, stringListMap);
if (stringListMap != null && stringListMap.get("Set-Cookie") != null)
for (String cookieValue: stringListMap.get("Set-Cookie")) {
cookiesStrings.add(cookieValue);
}
}
}
现在一切正常:)
要从响应中获取多个 "Set-Cookie" header :
Call<LoginResponse> call = apiService.login(loginRequest);
call.enqueue(new Callback<LoginResponse>() {
@Override
public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
showProgress(false);
if (response.body() != null) {
LoginResponse loginResponse = response.body();
//Get headers from response
Headers headerResponse = response.headers();
//convert header to Map
Map<String, List<String>> headerMapList = headerResponse.toMultimap();
//Get List of "Set-Cookie" from Map
List<String> allCookies = headerMapList.get("Set-Cookie");
String cookieval = "";
for (int i = 1; i < allCookies.size(); i++) {
allCookies.get(i);
//concat all cookies in cookieval.
cookieval = cookieval + allCookies.get(i);
}
//Save cookies value in Application class.
((AppConfig) getApplication()).setCookies(cookieval);
((AppConfig) getApplication()).setUserInfo(loginResponse);
if (loginResponse.getStatus().equals("ok")) {
startActivity(new Intent(LoginActivity.this, MainActivity.class));
mAuthTask = true;
finish();
} else {
mPasswordView.setError(getString(R.string.error_incorrect_password));
mPasswordView.requestFocus();
}
}
}
@Override
public void onFailure(Call<LoginResponse> call, Throwable t) {
Log.d(TAG, "onFailure: ");
mAuthTask = false;
}
});
传递其他服务中的所有 cookie(例如注销服务)
@Headers({"Content-Type: application/json"})
@POST("request/get/user/logout")
Call<LogoutResponse> logout(@Header("Cookie") String cookie);
在Api界面添加这段代码
现在像这样调用注销服务:
Call<LogoutResponse> call = apiService.logout(((AppConfig) getApplication()).getCookies());
call.enqueue(new Callback<LogoutResponse>() {
@Override
public void onResponse(Call<LogoutResponse> call, Response<LogoutResponse> response) {
if(response.body() != null){
LogoutResponse logoutResponse = response.body();
if (logoutResponse.getStatus().equals("ok")) {
finish();
startActivity(new Intent(MainActivity.this, LoginActivity.class));
}
}
}
@Override
public void onFailure(Call<LogoutResponse> call, Throwable t) {
Log.d(TAG, "onFailure: ");
}
});
您可以使用 Kotlin 编写扩展函数。
fun Headers.getCookies(): String? {
var cookieString: String? = null
this.toMultimap()["Set-Cookie"]?.forEach {
cookieString += it
}
return cookieString
}
您可以使用 response.headers().values("some_header")
获取 header
val authCookies = mutableMapOf<String, String>()
val response = restManager.login(AuthDto().apply {
clientId = agent.clientId
apiKey = "awesome_api_key"
}).execute()
response.headers().values("Set-Cookie").forEach {
if (it.startsWith("auth=")) {
authCookies["auth"] = it
} else {
authCookies["refresh"] = it
}
}