Getting Header from Response (Retrofit/Okhttp Client)

Getting Header from Response (Retrofit / OkHttp Client)

With Retrofit 1.9.0, if you use the Callback asynchronous version of the interface,

@GET("/user")
void getUser(Callback<User> callback)

Then your callback will receive a Response object

    Callback<User> user = new Callback<User>() {
@Override
public void success(User user, Response response) {

}

@Override
public void failure(RetrofitError error) {

}
}

Which has a method called getHeaders()

    Callback<User> user = new Callback<User>() {
@Override
public void success(User user, Response response) {
List<Header> headerList = response.getHeaders();
for(Header header : headerList) {
Log.d(TAG, header.getName() + " " + header.getValue());
}
}

For Retrofit 2.0's interface, you can do this with Call<T>.

For Retrofit 2.0's Rx support, you can do this with Observable<Result<T>>

Retrofit not getting all header response

After trying everything I found on the internet, finally I noticed the Authorization Bearer token is not being sent because I wrote "Authentication" as header name instead of "Authorization" . I have corrected that and it's working perfectly now. But anyone who wants to mess around with headers or cookies , here are few ways :

  • Use CookieJar for cookies
  • Use network interceptors for headers or cookies

Cookiejar example :

         final HashMap<String, List<Cookie>> cookieStore = new HashMap<>();

CookieJar cookiejar = new CookieJar() {
@Override
public void saveFromResponse(@NotNull HttpUrl httpUrl, @NotNull List<Cookie> list) {

Log.d(TAG, "saveFromResponse: "+ cookie.name() +":"+ cookie.value());

cookieStore.put(httpUrl.host(), list);

}

@NotNull
@Override
public List<Cookie> loadForRequest(@NotNull HttpUrl httpUrl) {
List<Cookie> cookies = cookieStore.get(httpUrl.host());
return cookies != null ? cookies : new ArrayList<Cookie>();
}
};

OkHttpClient client ;
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.cookieJar(cookiejar);
client = builder.build();

HttpLoggingInterceptor example:

 HttpLoggingInterceptor logging = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
@Override
public void log(@NotNull String s) {
Log.d("logevent", s); // this will run in loop until finishes reading all headers
}
}).setLevel(HttpLoggingInterceptor.Level.HEADERS);


OkHttpClient client ;
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.addNetworkInterceptor(logging);
client = builder.build();

For reading headers , ReceivedCookiesInterceptor example:

import android.content.Context;

import android.util.Log;

import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import okhttp3.Headers;
import okhttp3.Interceptor;
import okhttp3.Response;

public class ReceivedCookiesInterceptor implements Interceptor {
private Context context;
public ReceivedCookiesInterceptor(Context context) {
this.context = context;
}

@Override
public Response intercept(Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());

//cookie headers only
if (!originalResponse.headers("Set-Cookie").isEmpty()) {

for (String header : originalResponse.headers("Set-Cookie")) {
Log.d(TAG, "cookie: "+header);
}

}

//for any other headers
Map m = originalResponse.headers().toMultimap();

Iterator it = m.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry)it.next();
Log.d(TAG, "intercept: "+pair.getKey() + " = " + pair.getValue());
it.remove();
}

return originalResponse;
}
}

for manipulating headers, AddCookiesInterceptor :

import android.content.Context;
import android.util.Log;
import java.io.IOException;
import java.util.HashSet;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;

public class AddCookiesInterceptor implements Interceptor {

public AddCookiesInterceptor(Context context) {
this.context = context;
}

@Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request.Builder builder = chain.request().newBuilder();



//for adding headers:
builder.addHeader("key", "value");

//for replacing headers:
builder.header("key", "value");

return chain.proceed(builder.build());
}
}

then just as before add these as interceptors. You might need to add these to your dependency :

implementation("com.squareup.okhttp3:logging-interceptor:4.9.0")
implementation "com.squareup.okhttp3:okhttp-urlconnection:3.6.0"

how to get response headers using Retrofit in Kotlin?

Word of advice rather than a solution

Not a question of solving your problem but even if it's late, as you're
using Kotlin, a better solution would be to migrate from rxJava to Kotlin Flow. It allows you to use suspend functions to do your retrofit calls, then use Kotlin Flow to do the rxJava's job on the IO thread.

It also allows you to use the Response<T> retrofit object in a simpler way.

Example:

The retrofit request

    @POST(YOUR_ROAD) // Retrofit road
suspend fun connect(
@Body credentials: CredentialsObjectBody
): Response<ConnectionObjectResponse>

The repository call to the retrofit request

    // The function is suspending the thread with suspend keyword
suspend fun yourFunction(): Flow<DataState<TypeForEmitter>> = flow {
try {
body.clientId = sessionPrefs.deviceName!!
val connectionResponse =
majorApi.connect(
// what you need to put in the body
)
.apply {
if (isSuccessful) {
body()?.let {
// Here you can use what's in the request body
emit(DataState.Success(it))
} ?: throw Exception("Request body was null")
} else {
throw Exception(headers()["message"]) // use throw to handle the error in the catch
}
}
} catch (e: Exception) {
Log.e(TAG, "error: ${e.message}")
emit(DataState.Error(e))
}
}

DataState:

DataState is a sealed class that allows to differentiate emitted status
    sealed class DataState<out R> {
data class Success<out T>(val data: T) : DataState<T>()
data class Error(val exception: Exception) : DataState<Nothing>()
object Loading : DataState<Nothing>()
}

How to call the Kotlin flow to launch it on IO thread to prevent blocking the Main (or UI) thread

    withContext(Dispatchers.IO) {
yourFunction().onEach {
/*
onEach is like onNext, but emits every type of error, compared to rxJava
that differentiates next/success, complete and error events
*/
}
}

How to get custom header from response (retrofit & rxjava)

Change your retrofit class to return a Response:

@POST("/register")
fun registerUser(@Body registerPostData: RegistrationForm): Single<Response<RegistrationResponse>>

then:

override fun onSuccess(result: Response<RegistrationResponse>?) {
// get header from response.headers()
}


Related Topics



Leave a reply



Submit