How to trap the 413 error in Play Framework? - java

I want to return a JSON response instead of HTML.
I dont know how to trap it.
For example i set the 'play.http.parser.maxMemoryBuffer' to 1MB, and if the request body will exceed 1 MB, it will return a JSON response but not HTML format saying that it is a bad response.

According to the documentation:
To switch from HTML to JSON response you can add this line to application.conf
play.http.errorHandler = play.http.JsonHttpErrorHandler
If you also want to customize the message, you should instead add this line to application.conf
play.http.errorHandler = "com.example.ErrorHandler"
Obviously, the line above, should point to your own implementation of the error handler, that could look like this:
package com.example
import play.http.HttpErrorHandler;
import play.mvc.*;
import play.mvc.Http.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import javax.inject.Singleton;
#Singleton
public class ErrorHandler implements HttpErrorHandler {
public CompletionStage<Result> onClientError(RequestHeader request, int statusCode, String message) {
if (statusCode == 413) {
return CompletableFuture.completedFuture(Results.status(statusCode, "A client error occurred: " + message + " The payload size should be lower than 1Mb."));
} else {
return CompletableFuture.completedFuture(Results.status(statusCode, "A client error occurred: " + message));
}
}
public CompletionStage<Result> onServerError(RequestHeader request, Throwable exception) {
return CompletableFuture.completedFuture(
Results.internalServerError("A server error occurred: " + exception.getMessage()));
}
}

Related

Passing array of strings to Java REST API using axios doesn't work

I am trying to send an array of strings using axios to a rest endpoint using jersey with spring boot and tomcat. It results in a 404 and I am clueless. The url being passed is correct because if I send a single string with GET it works correctly.
EDIT: Any exception within any another endpoint (say NullPointerException) also results in 404 being shown in the browser. This is something to do with the configuration. So 404 is kind of a red herring status code.
This is my java side code
import org.springframework.stereotype.Component;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import java.util.*;
#Component
#Path("v1/")
public class SomeResourceV1 {
#POST
#Path("delete")
#Consumes(MediaType.APPLICATION_JSON)
public void deleteFoo(List<String> ids) {
if (ids != null) {
// do something
}
}
}
This is the typescript code:
public delete(someIds : string[]) {
axios({
method: 'POST',
url: "/v1/delete",
data: someIds
}).then((response : any) => {
}).catch((error) => {
console.log("*** delete error ***", error);
});
}
I have also tried to send data as
data:{
ids: someIds
}
I have also attempted to use transformRequest but to no avail.
How does I fix this? Thanks for the help!

Error with "Premature end of Content-Length delimited message body (expected: 349; received: 0)"

When performing a POST request to the server, and I call readEntity, I am presented with the error "Premature end of Content-Length delimited message body (expected: 349; received: 0)".
At first, I thought the server was returning me 0 bytes, but when making the same request via postman, the return comes correctly. I also captured the network packets with WireShark, what I could see in the packages is that the header comes in one package and the body in another. I don't know if that would be the problem. Another thing I noticed is that the connection is terminated with an RST, as shown below:
https://i.ibb.co/MSGhHJM/Wire-Shark.png
Following is code snippets, where the line that occurs the error is: params = post.readEntity(HashMap.class);
Config class imports:
import com.google.inject.Inject;
import org.jose4j.json.internal.json_simple.JSONArray;
import javax.ws.rs.core.Response;
import java.util.HashMap;
Config class:
public void configure(SchedulerModule module, SessionInfo session) {
Response post = connection.post(session, ServiceURL.CONFIG_URL, new JSONArray());
params = post.readEntity(HashMap.class); // Linha que o erro ocorre
if ("R".equals(params.get("IE_TIPO")) && validaInteger(params.get("QT_INTERVALO")) > 0) {
module.setDelay(validaInteger(params.get("QT_INTERVALO")));
module.setRate(validaInteger(params.get("QT_INTERVALO")));
isRun = true;
} else {
isRun = false;
}
}
Connection class imports:
import com.google.inject.Inject;
import com.google.inject.name.Named;
import org.jose4j.json.internal.json_simple.JSONArray;
import org.jose4j.json.internal.json_simple.JSONObject;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.stream.Collectors;
Connection class method:
public Response post(SessionInfo sessionInfo, ServiceURL url, JSONArray array) {
Client client = ClientBuilder.newClient();
try {
Invocation.Builder builder = client.target(backendUrl).path(url.getUrl())
.request(MediaType.APPLICATION_JSON_TYPE)
.header("idSessao", sessionInfo.getIdSessao())
.header("crsfToken", sessionInfo.getCrsfToken())
.header("Cookie", sessionInfo.getCookieHeader());
return builder.post(Entity.entity(array == null ? "[]" : array.toString(), MediaType.APPLICATION_JSON_TYPE));
} catch (Exception e) {
System.out.println("Failure" + e.getMessage());
} finally {
client.close();
}
return null;
}
I need to get the return body of this request. Can you help me?

Play framework error: not found: value message

I have a route, controller and view defined. When I do a get request for the home directory, which is "/", I am getting the error not found: value message. index.scala.html:2.
routes:
GET / controllers.HomeController.index(message: String, name: String)
GET /count controllers.CountController.count
GET /message controllers.AsyncController.message
GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset)
index.scala.html:
#(name: String)
#(message: String)
#main("Welcome to Sparta") {
#welcome(message, style = "java")
}
HomeController.java:
package controllers;
import play.mvc.*;
import play.*;
import views.html.*;
import java.util.Date;
public class HomeController extends Controller {
public String name;
public String message;
public Result index(String name, String message) {
name = "TEST NAME";
message = "Test message";
return ok(name, "message: " + message);
}
}
Why is the error telling me I have not defined a value for message?
Your route and index method in the controller is not correct. If you are sending any parameters to the server, they come into the picture. Your URL does look like you are sending some parameter with it, so please remove parameters for the index method.
public Result index() {
name = "TEST NAME";
message = "Test message";
return ok(name, "message: " + message);
}

How to capture the requests using JAVA servlets

I need to capture all the http/https requests that are going through the browsers of my system using JAVA servlets.
Can I achieve that?
going through the browsers of my system
You can do this is with an implementation of ServletRequestListener::requestInitialized(ServletRequestEvent sre)
The Documentation say:
requestInitialized(ServletRequestEvent sre)
Receives notification that a ServletRequest is about to come into scope of the web application.
The class could look like this:
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.Map.Entry;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServletRequest;
#WebListener
public class RequestListener implements ServletRequestListener {
public RequestListener() {}
public void requestDestroyed(ServletRequestEvent sre) {}
public void requestInitialized(ServletRequestEvent sre) {
HttpServletRequest request = (HttpServletRequest) sre.getServletRequest();
System.out.println("Timestamp: " + new Timestamp(System.currentTimeMillis()));
System.out.println("SessionId: " + request.getSession(false));
System.out.println("RequestURL: " + request.getRequestURL());
System.out.println("Method: " + request.getMethod());
System.out.println("Parameters: ");
for (Entry<String, String[]> entry : request.getParameterMap().entrySet()) {
System.out.println(entry.getKey() + " = " + Arrays.asList(entry.getValue()));
}
}
}
In the console you get something like this:
Timestamp: 2017-01-25 19:12:04.36
SessionId: null
RequestURL: https://localhost:8181/jee6/ResponseFilterTest/Fiz
Method: GET
Parameters:
p1 = [v1]
p2 = [v2]
Instead in the console you can store the data in a DB or write to a log.
If you need to differentiate between local and remote requests you can use request.getRemoteAddr(). For local requests it is 127.0.0.1

Retrofit #GET - how to display request string?

I'm working on an Android application that uses Retrofit to create a restful client. In order to debug networks calls, I would like to display or dump the url that's actually being invoked. Is there a way to do this? I've included some code below which shows how the app currently using retrofit.
Client interface definition:
import retrofit.Callback;
import retrofit.http.Body;
import retrofit.http.GET;
import retrofit.http.Headers;
import retrofit.http.POST;
import retrofit.http.Path;
// etc...
public interface MyApiClient {
#Headers({
"Connection: close"
})
#GET("/{userId}/{itemId}/getCost.do")
public void get(#Path("userId") String userId, #Path("itemId") String userId, Callback<Score> callback);
//....etc
}
Service which uses generated client:
// etc...
import javax.inject.Inject;
import retrofit.Callback;
import retrofit.RetrofitError;
import retrofit.client.Response;
#Inject
MyApiClient myApiClient;
// etc...
myApiClient.getCost(myId, itemId, new Callback<Cost>() {
#Override
public void success(Cost cost, Response response) {
Log.d("Success: %s", String.valueOf(cost.cost));
if (cost.cost != -1) {
processFoundCost(cost);
} else {
processMissingCost(itemId);
}
stopTask();
}
#Override
public void failure(RetrofitError error) {
handleFailure(new CostFailedEvent(), null);
}
});
}
call.request().url(), where call is type of retrofit2.Call.
RetrofitError has a getUrl() method that returns the URL.
Also the Response has a getUrl() method as well within the callback.
That, and you can also specify the log level as per this question:
RestAdapter adapter = (new RestAdapter.Builder()).
//...
setLogLevel(LogLevel.FULL).setLog(new AndroidLog("YOUR_LOG_TAG"))
Although based on the docs, LogLevel.BASIC should do what you need.
BASIC
Log only the request method and URL and the response status code and execution time.
Yes, you can enable debug logging by calling setLogLevel() on your RestAdapter.
I typically set logging to LogLevel.FULL for debug builds like so:
RestAdapter adapter = builder.setEndpoint("example.com")
.setLogLevel(BuildConfig.DEBUG ? RestAdapter.LogLevel.FULL : RestAdapter.LogLevel.NONE)
.build();
This will automatically print out all of the information associated with your HTTP requests, including the URL you are hitting, the headers, and the body of both the request and the response.

Categories