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
Searchview Getactionview Returning Null
How Can Android Source Code Not Have a Main Method and Still Run
Android: Changing Nfc Settings (On/Off) Programmatically
Android Camera: Onactivityresult() Intent Is Null If It Had Extras
Android: Google Maps Location with Low Battery Usage
Savedinstancestate Is Always Null in Fragment
Gradle Flavors for Android with Custom Source Sets - What Should the Gradle Files Look Like
Android Studio 3.0 Compile Issue (Cannot Choose Between Configurations)
How to Import a .Aar File into Android Studio 1.1.0 and Use It in My Code
How to Use Mediacodec Without Mediaextractor for H264
Gesture Detection and Scrollview Issue
Filling a Circle Gradually from Bottom to Top Android
Communication Between Broadcastreceiver and Activity - Android
Findfragmentbytag() Returns Null After Perform a Fragmenttransaction Using Replace() Method