When sending POST requests to an API endpoint using #FormUrlEncoded from RetroFit2, the record looked scrambled when it was Japanese but ok when English.
The charset was set to null when using to send POST request.
Content-Type:application/x-www-form-urlencoded was the header instead of Content-Type:application/x-www-form-urlencoded; charset=utf-8
#FormUrlEncoded
#POST("/api/items")
Call<ApiResponse> post(#FieldMap Map<String, Object> fields);
2 Solutions:
add the headers manually for each endpoint, not very scaleable solution
#FormUrlEncoded
#POST("/api/items")
#Headers("Content-Type:application/x-www-form-urlencoded; charset=utf-8")
Call<ApiResponse> post(#FieldMap Map<String, Object> fields);
add an interceptor to add it for endpoints having POST, a bit more verbose:
#Bean
public ApiService apiService(final ObjectMapper objectMapper) {
final OkHttpClient httpClient = new OkHttpClient.Builder().addInterceptor(chain -> {
final Request original = chain.request();
if (original.method().equals("POST")) {
final Buffer buffer = new Buffer();
original.body().writeTo(buffer);
final String content = buffer.readString(StandardCharsets.UTF_8);
final RequestBody body = RequestBody.create(MediaType.parse(""application/x-www-form-urlencoded"), content);
final Request request = original.newBuilder().method(original.method(), body).build();
return chain.proceed(request);
} else {
return chain.proceed(original);
}
}).build();
final Retrofit retrofit = new Retrofit.Builder()
.client(httpClient)
.baseUrl(apiBaseUrl)
.build();
return retrofit.create(ApiService.class);
}
Related
I am add a interpreter in retrofit like this:
public static Retrofit InitRetrofitOkhttp(String configKey) {
String tenantId = MyContext.getCurrentTenantId() == null ? "" : MyContext.getCurrentTenantId().toString();
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(10, TimeUnit.SECONDS);
builder.readTimeout(20, TimeUnit.SECONDS);
builder.writeTimeout(20, TimeUnit.SECONDS);
builder.retryOnConnectionFailure(true);
builder.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
Request.Builder requestBuilder = original.newBuilder()
.header(MyContext.VERIFY_TENANT_ID, tenantId);
Request request = requestBuilder.build();
return chain.proceed(request);
}
});
Config config = ConfigService.getAppConfig();
String baseUrl = config.getProperty(configKey, "127.0.0.1");
OkHttpClient client = builder.build();
Retrofit.Builder retrofitBuilder = new Retrofit.Builder();
retrofitBuilder.client(client);
retrofitBuilder.baseUrl(baseUrl);
retrofitBuilder.addConverterFactory(GsonConverterFactory.create());
Retrofit sRetrofit = retrofitBuilder.build();
return sRetrofit;
}
what I want to do is add different tenant_id in every http request, but it seems only the first time initial retrofit add interpreter(I could not debbugging in interpreter), what should I do to make it work? I did not know I do like this works.
Move
String tenantId = MyContext.getCurrentTenantId() == null ? "" : MyContext.getCurrentTenantId().toString();
into intercept method
I'm trying to fetch a stored JWT from the SharedPreferences so I can send them as a Header in my requrest but I'm not able to get that data inside the API interface. Is this possible?
Thanks
SOLVED:
For anyone looking for this: you can pass a Header as a param, ex.:
#FormUrlEncoded
#POST("users/getUser")
Call<String> getUser(
#Header("Token") String token,
#Field("user") String user
);
also you can use an integrated Interceptor to adding this token on ALL requests like this:
public class AuthInterceptor
implements Interceptor {
#Override
public Response intercept(Chain chain)
throws IOException {
Request request = chain.request();
request = request.newBuilder()
.addHeader("Token", new MySharedPref().getToken())
.build();
return chain.proceed(request);
}
}
and after that add an instance of it on your OkHttpClient :
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addNetworkInterceptor(new AuthInterceptor());
Retrofit retrofit = new Retrofit.Builder()
...
.client(httpClient.build())
.build();
When my Java web application receives an HTTP POST request, it needs to create a new OkHttp3 Request from the HttpServletRequest and send this to another URL. The original post request could be simple form data or multi-part.
Here's the interface that I am looking to implement:
import okhttp3.Request;
public interface OkHttp3RequestBuilder {
Request create(HttpServletRequest request);
}
Looks like the challenge boils down to how I would create an okhttp3.RequestBody. Here's the relevant part of the implementation...
final HttpUrl targetUrl = HttpUrl.get("http://internal.xyz.com");
final RequestBody requestBody = // ?????
final Request httpRequest = new Request.Builder()
.post(requestBody)
.url(targetUrl)
.build();
return httpRequest;
How do I go about doing it? Any suggestions? Thanks!
This should work, but request.getReader() must never have been called as you can call it only once.
Request create(HttpServletRequest request)
{
final HttpUrl targetUrl = HttpUrl.get("http://internal.xyz.com");
final String originalBody = request.getReader().lines().collect (Collectors.joining (System.lineSeparator()));
final RequestBody requestBody = RequestBody.create(MediaType.parse(request.getContentType()), originalBody);
final Request httpRequest = new Request.Builder()
.post(requestBody)
.url(targetUrl)
.build();
return httpRequest;
}
Thanks for your answer, ETL! This seems to work for me:
#Override
public RequestBody getRequestBody(final HttpServletRequest httpServletRequest) throws IOException {
final InputStream inputStream = httpServletRequest.getInputStream();
final byte[] requestBodyBytes = ByteStreams.toByteArray(inputStream);
final String contentType = httpServletRequest.getContentType();
final MediaType mediaType = MediaType.parse(contentType);
final RequestBody requestBody = RequestBody.create(mediaType, requestBodyBytes);
return requestBody;
}
I have a token which i save to sharedPreferences and then i get that token and pass it as an authorization to a Retrofit requests. This is my codes below which i used to add a header to my retrofit requests.
I need to add the header below:
"Authorization" "Bearer" + token
public static Retrofit getClient(String token) {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient okClient = new OkHttpClient();
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
.create();
okClient.interceptors().add(chain -> {
Response response = chain.proceed(chain.request());
return response;
});
okClient.interceptors().add(chain -> {
Request original = chain.request();
Request request = original.newBuilder()
.header("Authorization", token)
.method(original.method(), original.body())
.build();
return chain.proceed(request);
});
okClient.interceptors().add(logging);
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(Config.BASE_URL1)
.client(okClient)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
}
return retrofit;
}
This how i send my token to the retrofit client
Retrofit retrofit = RetrofitClient.getClient("Bearer" + " " + authUser.getToken());
APIService mAPIService = retrofit.create(APIService.class);
But unfortunately the server responds with the message no authorization
You can send header to server without using an interceptor. Just add a field in your method declaration in your service interface like this:
#GET("my/orders/{id}")
Call<Order> getOrder(#Header("Authorization") String token,
#Path("id") int order_id);
Then create a Call object to send request as below:
APIService apiService= retrofit.create(APIService.class);
Call<Order> call = apiService.getOrder(token, id);
call.enqueue(/*callback*/);
Add a method in the BaseCaller Class for your headers like below:
public HashMap<String, String> getHeaders() {
HashMap<String, String> headerHashMap = new HashMap<>();
headerHashMap.put("Content-Type", "application/x-www-form-urlencoded");
headerHashMap.put("time_zone_name", DateTimeHelper.getTimeZoneName());
headerHashMap.put("gmt_offset", DateTimeHelper.getGMTOffset());
return headerHashMap;
}
Now create a method in your service class for url like :
#FormUrlEncoded
#POST("switch_user")
Call<JsonObject> switchUser(#HeaderMap Map<String, String> headers, #FieldMap Map<String, String> fields);
Finally in your class caller class call the methods as follows :
call = loginService.switchUser(getHeaders(), apiParams.mHashMap);
This will do the needful :)
Try this for same:
String credentials = "put your token here";
final String basic = "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
Request.Builder requestBuilder = original.newBuilder()
.header("Authorization",basic);
I'm looking for a solution to define a unique Header to use in all requests. Today I use #Header to each request did pass like parameter but I want define only header that works in all requests without to need pass like a parameter, for example fixing this Header on my requests #GET and #POST
Today I use this. Note that each request #GET I need define Header as parameter.
//interface
#GET("/json.php")
void getUsuarioLogin(
#Header("Authorization") String token,
#QueryMap Map<String, String> params,
Callback<JsonElement> response
);
//interface
#GET("/json.php")
void addUsuario(
#Header("Authorization") String token,
#QueryMap Map<String, String> params,
Callback<JsonElement> response
);
//using
public void getUsuarioLogin(){
Map<String, String> params = new HashMap<String, String>();
params.put("email", "me#mydomain.com");
params.put("senha", ConvertStringToMD5.getMD5("mypassword"));
RestAdapter adapter = new RestAdapter.Builder()
.setLogLevel(RestAdapter.LogLevel.FULL)
.setEndpoint(WebServiceURL.getBaseWebServiceURL())
.build();
UsuarioListener listener = adapter.create(UsuarioListener.class);
listener.getUsuarioLogin(
//header
"Basic " + BasicAuthenticationRest.getBasicAuthentication(),
params,
new Callback<JsonElement>() {
#Override
public void success(JsonElement arg0, Response arg1) {
Log.i("Usuario:", arg0.toString() + "");
}
#Override
public void failure(RetrofitError arg0) {
Log.e("ERROR:", arg0.getLocalizedMessage());
}
});
}
//using
public void addUsuario(){
Map<String, String> params = new HashMap<String, String>();
params.put("name", "Fernando");
params.put("lastName", "Paiva");
RestAdapter adapter = new RestAdapter.Builder()
.setLogLevel(RestAdapter.LogLevel.FULL)
.setEndpoint(WebServiceURL.getBaseWebServiceURL())
.build();
UsuarioListener listener = adapter.create(UsuarioListener.class);
listener.addUsuario(
//header
"Basic " + BasicAuthenticationRest.getBasicAuthentication(),
params,
new Callback<JsonElement>() {
#Override
public void success(JsonElement arg0, Response arg1) {
Log.i("Usuario:", arg0.toString() + "");
}
#Override
public void failure(RetrofitError arg0) {
Log.e("ERROR:", arg0.getLocalizedMessage());
}
});
}
Official document:
Headers that need to be added to every request can be specified using a RequestInterceptor. The following code creates a RequestInterceptor that will add a User-Agent header to every request.
RequestInterceptor requestInterceptor = new RequestInterceptor() {
#Override
public void intercept(RequestFacade request) {
request.addHeader("User-Agent", "Retrofit-Sample-App");
}
};
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint("https://api.github.com")
.setRequestInterceptor(requestInterceptor)
.build();
In Retrofit 2, you need to intercept the request on the network layer provided by OkHttp
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
Request request = original.newBuilder()
.header("User-Agent", "Your-App-Name")
.header("Accept", "application/vnd.yourapi.v1.full+json")
.method(original.method(), original.body())
.build();
return chain.proceed(request);
}
}
OkHttpClient client = httpClient.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
Check this, it explains the differences very well.
Depending on your OkHttp lib:
OkHttpClient httpClient = new OkHttpClient();
httpClient.networkInterceptors().add(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request().newBuilder().addHeader("User-Agent", System.getProperty("http.agent")).build();
return chain.proceed(request);
}
});
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(httpClient)
.build();
As the other answers have described, you need a RequestInterceptor. Luckily, this interface has a single method, so Java 8 and above will treat it as a functional interface and let you implement it with a lambda. Simple!
For example, if you're wrapping a specific API and need a header for each endpoint, you might do this when you build your adapter:
RestAdapter whatever = new RestAdapter.Builder().setEndpoint(endpoint)
.setRequestInterceptor(r -> r.addHeader("X-Special-Vendor-Header", "2.0.0"))
.build()
Here's the solution for adding header using retrofit 2.1. We need to add interceptor
public OkHttpClient getHeader(final String authorizationValue ) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient okClient = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.addNetworkInterceptor(
new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request request = null;
if (authorizationValue != null) {
Log.d("--Authorization-- ", authorizationValue);
Request original = chain.request();
// Request customization: add request headers
Request.Builder requestBuilder = original.newBuilder()
.addHeader("Authorization", authorizationValue);
request = requestBuilder.build();
}
return chain.proceed(request);
}
})
.build();
return okClient;
}
Now in your retrofit object add this header in the client
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url)
.client(getHeader(authorizationValue))
.addConverterFactory(GsonConverterFactory.create())
.build();