I'm using Retrofit to do a basic POST request, and I'm providing a basic @Body for the request.
@POST("/rest/v1/auth/login")
LoginResponse login(@Body LoginRequest loginRequest);
When I'm building the interface for Retrofit I'm providing my own custom OkHttpClient, and all that I'm doing to it is adding my own custom authentication:
@Provides
@Singleton
public Client providesClient() {
OkHttpClient httpClient = new OkHttpClient();
httpClient.setAuthenticator(new OkAuthenticator() {
@Override
public Credential authenticate(Proxy proxy, URL url, List<Challenge> challenges) throws IOException {
return getCredential();
}
@Override
public Credential authenticateProxy(Proxy proxy, URL url, List<Challenge> challenges) throws IOException {
return getCredential();
}
});
return new OkClient(httpClient);
}
This works great when I'm sending requests directly with OKHttp, and other GET requests with retrofit but when I use retrofit to do a POST request I get the following error:
Caused by: java.net.HttpRetryException: Cannot retry streamed HTTP body
at com.squareup.okhttp.internal.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:324)
at com.squareup.okhttp.internal.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:508)
at com.squareup.okhttp.internal.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:136)
at retrofit.client.UrlConnectionClient.readResponse(UrlConnectionClient.java:94)
at retrofit.client.UrlConnectionClient.execute(UrlConnectionClient.java:49)
at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:357)
at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.java:282)
at $Proxy3.login(Native Method)
at com.audax.paths.job.LoginJob.onRunInBackground(LoginJob.java:41)
at com.audax.library.job.AXJob.onRun(AXJob.java:25)
at com.path.android.jobqueue.BaseJob.safeRun(BaseJob.java:108)
at com.path.android.jobqueue.JobHolder.safeRun(JobHolder.java:60)
at com.path.android.jobqueue.executor.JobConsumerExecutor$JobConsumer.run(JobConsumerExecutor.java:172)
at java.lang.Thread.run(Thread.java:841)
I've played around with it. If I remove the authentication, and point to a server that doesn't require the authentication, then it works fine.
Not sure how to get around this. Any help would be wonderful.
Thanks, Jesse.
Just in case it helps, here is the code I did for Basic auth.
First, the init in MyApplication
class:
ApiRequestInterceptor requestInterceptor = new ApiRequestInterceptor();
requestInterceptor.setUser(user); // I pass the user from my model
ApiService apiService = new RestAdapter.Builder()
.setRequestInterceptor(requestInterceptor)
.setServer(Constants.API_BASE_URL)
.setClient(new OkClient()) // The default client didn't handle well responses like 401
.build()
.create(ApiService.class);
And then the ApiRequestInterceptor
:
import android.util.Base64;
import retrofit.RequestInterceptor;
/**
* Interceptor used to authorize requests.
*/
public class ApiRequestInterceptor implements RequestInterceptor {
private User user;
@Override
public void intercept(RequestFacade requestFacade) {
if (user != null) {
final String authorizationValue = encodeCredentialsForBasicAuthorization();
requestFacade.addHeader("Authorization", authorizationValue);
}
}
private String encodeCredentialsForBasicAuthorization() {
final String userAndPassword = user.getUsername() + ":" + user.getPassword();
return "Basic " + Base64.encodeToString(userAndPassword.getBytes(), Base64.NO_WRAP);
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}