添加 cookie 以改造 2 请求
Add cookies to retrofit 2 request
我需要使用 retrofit 2.0 添加 cookie。如果我理解正确,cookies - 与 headers 相同。必须添加此 cookie:
private HashMap<String, String> cookies = new HashMap();
cookies.put("sessionid", "sessionId");
cookies.put("token", "token");
这个与 Jsoup 库一起工作:
String json = Jsoup.connect(apiURL + "/link")
.cookies(cookies)
.ignoreHttpErrors(true)
.ignoreContentType(true)
.execute()
.body();
这是我的改造请求代码:
@GET("link")
Call<CbGet> getData(@Header("sessionid") String sessionId, @Header("token") String token);
但这是行不通的...
我收到 403 错误代码,因此请求中没有 cookie...
有什么想法吗?
首先:cookie 与 header 不同。 Cookie 是一种特殊的 HTTP header,名为 Cookie,后跟键值对列表(以“;”分隔)。类似于:
Cookie: sessionid=sessionid; token=token
因为 you cannot set multiple Cookie headers in the same request 你不能对单独的值使用两个 @Header 注释(sessionid和样本中的 token)。我可以想到一个 非常 hacky 解决方法:
@GET("link")
Call<CbGet> getData(@Header("Cookie") String sessionIdAndToken);
您更改方法以在一个字符串中发送 sessionId 和令牌。所以在这种情况下,您应该事先手动生成 cookie 字符串。在你的情况下 sessionIdAndToken String object 应该等于 "sessionid=here_goes_sessionid; token=here_goes_token"
正确的解决方案 是通过添加 OkHttp 来设置 cookie(即 Retrofit 用于进行底层 http 调用的库)request interceptor. You can see solution or adding custom headers here.
要将 cookie header 添加到 okhttp 请求 headers ,请在拦截器中添加:
request= request.newBuilder().addHeader("Cookie", sessionIdAndToken).build();
参考:https://github.com/square/okhttp/wiki/Interceptors 如@Alexander Mironov 所述
此处为完整示例代码:希望对您有所帮助
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.List;
public class LoggingInterceptor implements Interceptor {
private static final Logger logger = LoggerFactory.getLogger(LoggingInterceptor.class);
@Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request request = chain.request();
long t1 = System.nanoTime();
request = processRequest(request);
logger.info("Sending request with url:{} and connection status:{} and request headers:{}",
request.url(), chain.connection(), request.headers());
Response response = chain.proceed(request);
long t2 = System.nanoTime();
logger.info("Received response for url:{} and time taken:{} and response headers as:{}",
response.request().url(), (t2 - t1) / 1e6d, response.headers());
response = processResponse(response);
return response;
}
//Add cookies for all subsequent requests
private Request processRequest(Request request) {
if(!request.url().toString().contains("/v1/authorize")) {
final EmployeeSession session = getSession();
StringBuilder etokenAndUId = new StringBuilder("etoken=");
etokenAndUId.append(session.getEtoken()).append(";").append("uId=").append(session.getUId());
logger.info("inside processRequest for all subsequent requests, sending cookies as etokenAndUId values:{}", etokenAndUId.toString());
request= request.newBuilder().addHeader("Cookie", etokenAndUId.toString()).build();
}
return request;
}
//Extract cookies from login url
private Response processResponse(Response response) {
if(response.request().url().toString().contains("/v1/authorize")) {
final List<String> cookieHeaders = response.headers("Set-Cookie");
String etoken = "", uId = "";
for (String cookieHeader : cookieHeaders) {
if(cookieHeader.contains("etoken=")) {
etoken = cookieHeader.substring(7, cookieHeader.indexOf(';'));
}
else if(cookieHeader.contains("uId=")) {
uId = cookieHeader.substring(4, cookieHeader.indexOf(';'));
}
}
logger.info("inside processResponse found cookies from login url response: etoken:{} and uid:{}", etoken, uId);
setSession(etoken, uId, "c1");
logger.info("current employee session:{}", getSession());
}
return response;
}
}
API Web 服务示例添加 Header
@FormUrlEncoded
@POST("getDriverRoutes")
Call<Guzergah> getGuzergah(@Header("Cookie") String userCookie, @Field("driver_id") int driver_id);
当您登录系统时,将 cookie 保存到您的本地响应
public void onResponse(Response<Login> response, Retrofit retrofit) {
hidepDialog();
String cookie = response.headers().get("Set-Cookie");
editor.putString("user_cookie", cookie.split(";")[0]);
editor.commit();
并且在您需要自动发送您的 cookie 的每项服务中,从 sharepreference 获取并将其与您的网络服务一起发送
String userCookie = shp.getString("user_cookie", ""); // here is cookies before send
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://server.aracadabra.com:8080/").
addConverterFactory(GsonConverterFactory.create())
.build();
final APIService service = retrofit.create(APIService.class);
final Call<SenMsgStatus> loginMCall = service.sendMessage(userCookie, type, route_id, user_id, passenger_id, passenger_status, text);
为什么不使用 cookieJar 选项?
new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(
new OkHttpClient().newBuilder()
.cookieJar(new SessionCookieJar()).build())
.build();
private static class SessionCookieJar implements CookieJar {
private List<Cookie> cookies;
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
if (url.encodedPath().endsWith("login")) {
this.cookies = new ArrayList<>(cookies);
}
}
@Override
public List<Cookie> loadForRequest(HttpUrl url) {
if (!url.encodedPath().endsWith("login") && cookies != null) {
return cookies;
}
return Collections.emptyList();
}
}
可以通过拦截器改造添加Cookie,这是我们在api请求中动态管理cookie的最佳方案。
我已经尝试过 JavaNetCookieJar(cookieManager) 这对我来说是行不通的。所以我为此使用拦截器,它也适用于依赖注入 n(匕首和 Koin)。
第 1 步: 创建 ReceivedCookiesInterceptor class 以接收 cookie。
Java代码:ReceivedCookiesInterceptor.java
public class ReceivedCookiesInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
if (!originalResponse.headers("Set-Cookie").isEmpty()) {
HashSet<String> cookies = new HashSet<>();
for (String header : originalResponse.headers("Set-Cookie")) {
cookies.add(header);
}
Preferences.getDefaultPreferences().edit()
.putStringSet(Preferences.PREF_COOKIES, cookies)
.apply();
}
return originalResponse;
}
}
科特林代码:ReceivedCookiesInterceptor.Kt
class ReceivedCookiesInterceptor : Interceptor {
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val originalResponse: Response = chain.proceed(chain.request())
if (originalResponse.headers("Set-Cookie").isNotEmpty()) {
val cookies: HashSet<String> = HashSet()
for (header in originalResponse.headers("Set-Cookie")) {
cookies.add(header)
}
preferenceProvider.putStringSet("PREF_COOKIES", cookies)
// Prefrence Provider In My SharedPrefrence Object
}
return originalResponse
}
}
第 2 步:创建 AddCookiesInterceptorclass 来存储 cookie。
Java代码:AddCookiesInterceptorclass.java
public class AddCookiesInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request.Builder builder = chain.request().newBuilder();
HashSet<String> preferences = (HashSet) Preferences.getDefaultPreferences().getStringSet(Preferences.PREF_COOKIES, new HashSet<>());
for (String cookie : preferences) {
builder.addHeader("Cookie", cookie);
Log.v("OkHttp", "Adding Header: " + cookie); // This is done so I know which headers are being added; this interceptor is used after the normal logging of OkHttp
}
return chain.proceed(builder.build());
}
}
科特林代码:AddCookiesInterceptorclass.kt
class AddCookiesInterceptor : Interceptor {
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val builder: Request.Builder = chain.request().newBuilder()
val prefCookies: HashSet<String> =
preferenceProvider.getStringSet("PREF_COOKIES", HashSet())
for (cookie in prefCookies) {
builder.addHeader("Cookie", cookie)
}
return chain.proceed(builder.build())
}
}
第 3 步:在您的 okHttpClientObject 中添加这些拦截器
Java代码:用于在Retrofit请求中添加拦截器
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.interceptors().add(new AddCookiesInterceptor());
okHttpClient.interceptors().add(new ReceivedCookiesInterceptor());
Kotlin 代码:用于在 Retrofit 请求中添加拦截器
val okHttpClient = OkHttpClient().newBuilder()
.connectionSpecs(specs)
.addInterceptor(requestInterceptor)
.addInterceptor(AddCookiesInterceptor())
.addInterceptor(ReceivedCookiesInterceptor())
我需要使用 retrofit 2.0 添加 cookie。如果我理解正确,cookies - 与 headers 相同。必须添加此 cookie:
private HashMap<String, String> cookies = new HashMap();
cookies.put("sessionid", "sessionId");
cookies.put("token", "token");
这个与 Jsoup 库一起工作:
String json = Jsoup.connect(apiURL + "/link")
.cookies(cookies)
.ignoreHttpErrors(true)
.ignoreContentType(true)
.execute()
.body();
这是我的改造请求代码:
@GET("link")
Call<CbGet> getData(@Header("sessionid") String sessionId, @Header("token") String token);
但这是行不通的... 我收到 403 错误代码,因此请求中没有 cookie...
有什么想法吗?
首先:cookie 与 header 不同。 Cookie 是一种特殊的 HTTP header,名为 Cookie,后跟键值对列表(以“;”分隔)。类似于:
Cookie: sessionid=sessionid; token=token
因为 you cannot set multiple Cookie headers in the same request 你不能对单独的值使用两个 @Header 注释(sessionid和样本中的 token)。我可以想到一个 非常 hacky 解决方法:
@GET("link")
Call<CbGet> getData(@Header("Cookie") String sessionIdAndToken);
您更改方法以在一个字符串中发送 sessionId 和令牌。所以在这种情况下,您应该事先手动生成 cookie 字符串。在你的情况下 sessionIdAndToken String object 应该等于 "sessionid=here_goes_sessionid; token=here_goes_token"
正确的解决方案 是通过添加 OkHttp 来设置 cookie(即 Retrofit 用于进行底层 http 调用的库)request interceptor. You can see solution or adding custom headers here.
要将 cookie header 添加到 okhttp 请求 headers ,请在拦截器中添加:
request= request.newBuilder().addHeader("Cookie", sessionIdAndToken).build();
参考:https://github.com/square/okhttp/wiki/Interceptors 如@Alexander Mironov 所述
此处为完整示例代码:希望对您有所帮助
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.List;
public class LoggingInterceptor implements Interceptor {
private static final Logger logger = LoggerFactory.getLogger(LoggingInterceptor.class);
@Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request request = chain.request();
long t1 = System.nanoTime();
request = processRequest(request);
logger.info("Sending request with url:{} and connection status:{} and request headers:{}",
request.url(), chain.connection(), request.headers());
Response response = chain.proceed(request);
long t2 = System.nanoTime();
logger.info("Received response for url:{} and time taken:{} and response headers as:{}",
response.request().url(), (t2 - t1) / 1e6d, response.headers());
response = processResponse(response);
return response;
}
//Add cookies for all subsequent requests
private Request processRequest(Request request) {
if(!request.url().toString().contains("/v1/authorize")) {
final EmployeeSession session = getSession();
StringBuilder etokenAndUId = new StringBuilder("etoken=");
etokenAndUId.append(session.getEtoken()).append(";").append("uId=").append(session.getUId());
logger.info("inside processRequest for all subsequent requests, sending cookies as etokenAndUId values:{}", etokenAndUId.toString());
request= request.newBuilder().addHeader("Cookie", etokenAndUId.toString()).build();
}
return request;
}
//Extract cookies from login url
private Response processResponse(Response response) {
if(response.request().url().toString().contains("/v1/authorize")) {
final List<String> cookieHeaders = response.headers("Set-Cookie");
String etoken = "", uId = "";
for (String cookieHeader : cookieHeaders) {
if(cookieHeader.contains("etoken=")) {
etoken = cookieHeader.substring(7, cookieHeader.indexOf(';'));
}
else if(cookieHeader.contains("uId=")) {
uId = cookieHeader.substring(4, cookieHeader.indexOf(';'));
}
}
logger.info("inside processResponse found cookies from login url response: etoken:{} and uid:{}", etoken, uId);
setSession(etoken, uId, "c1");
logger.info("current employee session:{}", getSession());
}
return response;
}
}
API Web 服务示例添加 Header
@FormUrlEncoded
@POST("getDriverRoutes")
Call<Guzergah> getGuzergah(@Header("Cookie") String userCookie, @Field("driver_id") int driver_id);
当您登录系统时,将 cookie 保存到您的本地响应
public void onResponse(Response<Login> response, Retrofit retrofit) {
hidepDialog();
String cookie = response.headers().get("Set-Cookie");
editor.putString("user_cookie", cookie.split(";")[0]);
editor.commit();
并且在您需要自动发送您的 cookie 的每项服务中,从 sharepreference 获取并将其与您的网络服务一起发送
String userCookie = shp.getString("user_cookie", ""); // here is cookies before send
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://server.aracadabra.com:8080/").
addConverterFactory(GsonConverterFactory.create())
.build();
final APIService service = retrofit.create(APIService.class);
final Call<SenMsgStatus> loginMCall = service.sendMessage(userCookie, type, route_id, user_id, passenger_id, passenger_status, text);
为什么不使用 cookieJar 选项?
new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(
new OkHttpClient().newBuilder()
.cookieJar(new SessionCookieJar()).build())
.build();
private static class SessionCookieJar implements CookieJar {
private List<Cookie> cookies;
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
if (url.encodedPath().endsWith("login")) {
this.cookies = new ArrayList<>(cookies);
}
}
@Override
public List<Cookie> loadForRequest(HttpUrl url) {
if (!url.encodedPath().endsWith("login") && cookies != null) {
return cookies;
}
return Collections.emptyList();
}
}
可以通过拦截器改造添加Cookie,这是我们在api请求中动态管理cookie的最佳方案。
我已经尝试过 JavaNetCookieJar(cookieManager) 这对我来说是行不通的。所以我为此使用拦截器,它也适用于依赖注入 n(匕首和 Koin)。
第 1 步: 创建 ReceivedCookiesInterceptor class 以接收 cookie。
Java代码:ReceivedCookiesInterceptor.java
public class ReceivedCookiesInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
if (!originalResponse.headers("Set-Cookie").isEmpty()) {
HashSet<String> cookies = new HashSet<>();
for (String header : originalResponse.headers("Set-Cookie")) {
cookies.add(header);
}
Preferences.getDefaultPreferences().edit()
.putStringSet(Preferences.PREF_COOKIES, cookies)
.apply();
}
return originalResponse;
}
}
科特林代码:ReceivedCookiesInterceptor.Kt
class ReceivedCookiesInterceptor : Interceptor {
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val originalResponse: Response = chain.proceed(chain.request())
if (originalResponse.headers("Set-Cookie").isNotEmpty()) {
val cookies: HashSet<String> = HashSet()
for (header in originalResponse.headers("Set-Cookie")) {
cookies.add(header)
}
preferenceProvider.putStringSet("PREF_COOKIES", cookies)
// Prefrence Provider In My SharedPrefrence Object
}
return originalResponse
}
}
第 2 步:创建 AddCookiesInterceptorclass 来存储 cookie。
Java代码:AddCookiesInterceptorclass.java
public class AddCookiesInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request.Builder builder = chain.request().newBuilder();
HashSet<String> preferences = (HashSet) Preferences.getDefaultPreferences().getStringSet(Preferences.PREF_COOKIES, new HashSet<>());
for (String cookie : preferences) {
builder.addHeader("Cookie", cookie);
Log.v("OkHttp", "Adding Header: " + cookie); // This is done so I know which headers are being added; this interceptor is used after the normal logging of OkHttp
}
return chain.proceed(builder.build());
}
}
科特林代码:AddCookiesInterceptorclass.kt
class AddCookiesInterceptor : Interceptor {
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val builder: Request.Builder = chain.request().newBuilder()
val prefCookies: HashSet<String> =
preferenceProvider.getStringSet("PREF_COOKIES", HashSet())
for (cookie in prefCookies) {
builder.addHeader("Cookie", cookie)
}
return chain.proceed(builder.build())
}
}
第 3 步:在您的 okHttpClientObject 中添加这些拦截器
Java代码:用于在Retrofit请求中添加拦截器
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.interceptors().add(new AddCookiesInterceptor());
okHttpClient.interceptors().add(new ReceivedCookiesInterceptor());
Kotlin 代码:用于在 Retrofit 请求中添加拦截器
val okHttpClient = OkHttpClient().newBuilder()
.connectionSpecs(specs)
.addInterceptor(requestInterceptor)
.addInterceptor(AddCookiesInterceptor())
.addInterceptor(ReceivedCookiesInterceptor())