I'm working with Facebook messenger app (chatbot) and I want to see what GET request I'm receiving from it. I'm using Spring Framework to start http server and ngrok to make it visible for facebook.
Facebook sending webhooks to me and i receive them, but i don't understand how to extract data from this request. Here what i get when I try HttpRequest to receive GET request. ngrok screenshot (error 500).
When I tried without HttpRequest, i had response 200 (ok).
What do i need to put to parameters of my find method to see GET request data?
My code:
#RestController
public class botAnswer {
#RequestMapping(method= RequestMethod.GET)
public String find(HttpRequest request) {
System.out.println(request.getURI());
String aaa = "222";
return aaa;
}
}
I guess HttpRequest will not help you here. For simplicity, just change HttpRequest to HttpServletRequest. You can access all query string parameters from it using request.getParameter("..."). Something like the following should work:
#RequestMapping(value = "/", method = RequestMethod.GET)
public String handleMyGetRequest(HttpServletRequest request) {
// Reading the value of one specific parameter ...
String value = request.getParameter("myParam");
// or all parameters
Map<String, String[]> params = request.getParameterMap();
...
}
This blog post shows how to use the #RequestParam annotation as an alternative to reading the parameters from HttpServletRequest directly.
Related
Sometimes we send a POST HTTP request with POST payload to an endpoint with URL variable, for example:
[POST] http://example.com/update-item?itemid=123456
To get the POST payload in the Spring controller class, I can do something this:
#RequestMapping(value = "/update-item", method = RequestMethod.POST)
public String updateItem(#RequestBody Item json) {
//some logics
return "/update-item-result";
}
However, at the same time, how can I get the variable from the URL (i.e. itemid in the above example) even for method = RequestMethod.POST?
I see a lot of Spring MVC examples on the web either get the GET variables from the URL or the POST variables from the payload, but I never see getting both in action.
You can use multiple HTTP requests by specifying the method attribute as an array in the #RequestMapping annotation.
#RequestMapping(value = "/update-item", method = {RequestMethod.POST,RequestMethod.GET})
public String updateItem(#RequestBody Item json) {
//some logics
return "/update-item-result";
}
I want to override the whitelabel error page. So as an example I have done this simple class:
#RestController
public class MyCustomErrorController implements ErrorController {
private static final String PATH = "/error";
#RequestMapping(value = PATH)
public String error() {
return "This is the error page";
}
#Override
public String getErrorPath() {
return PATH;
}
}
I have taken my example from here:
https://gist.github.com/jonikarppinen/662c38fb57a23de61c8b
According to that gist, it actually has a comment like this:
// Appropriate HTTP response code (e.g. 404 or 500) is automatically set by Spring.
// Here we just define response body.
However that's not what I'm seeing. For instance if I hit to a URL that I know that it should respond me a 500 status code (intentional NullPointerException), then that's what I should see, but when I hit to that URL I get a 200 response back with my error message ("This is the error page")
If I don't use this custom controller, then it shows me a 500 error page with the stacktrace on it, which is the default behavior. I have seen an old issue opened in 2014 here:
https://github.com/spring-projects/spring-boot/issues/684 that someone mentioning the same problem, however their solution is to show explicitly 500 responses, which does not really pass through the HTTP response code.
Just for the record, I actually put a breakpoint to org.apache.catalina.connector.Response.sendError() method. When this custom error controller does not exist, I can clearly see that sendError() method is being called with a status 500. However if I were to add HttpServletResponse argument to my error() method I do not see that the instance has 500 status code set.
Explanation
In the website example you provided, the HttpStatus is retrieved from the injected HttpServletResponse.
So the following:
Appropriate HTTP response code (e.g. 404 or 500) is automatically set by Spring.
means
Spring sets it on the HttpServletResponse that he gets injected into his method as
argument.
He then has to retrieve the status and set it on his model ErrorJson.
Solution
To follow your example, you could change your method to this:
#RequestMapping(value = ERROR_MAPPING)
public ResponseEntity<String> error(HttpServletResponse response) {
return new ResponseEntity<String>("This is the error page",
HttpStatus.valueOf(response.getStatus()));
}
I used ResponseEntity<String> instead of defining a custom object (a.k.a. ErrorJson).
As I believe you know, alternatively to using the HttpServletResponse's status, you could just set yours with HttpStatus.
Here you are simply returning a message from one method, which is not an error as per SpringBoot.
Following method will help you to return http status code as you want :
#RequestMapping(value = PATH)
public ResponseEntity<Map<String, Object>> error() {
Map<String, Object> map = new HashMap<>();
String statusMessage = "This is the error page";
String statusCode = HttpStatus.BAD_REQUEST.value();
map.put(STATUS_CODE, statusCode);
map.put(STATUS_MESSAGE, statusMessage);
return ResponseEntity.badRequest().body(map);
}
I am trying to send a JSON string as a request to my application. This is my code:
#RequestMapping(
value = "/mylink/upload",
method = RequestMethod.POST,
consumes ="application/json",
produces = "application/json")
public
#ResponseBody
List<Upload> upload(
#RequestParam(value = "hdfsLocation") String hdfsLocation
) throws Exception {
return S3HdfsTransfer.uploadFromHDFS(hdfsLocation);
}
I am trying to send a request with Postman. The method I use is POST, the header contains: Accept "application/json",Content-Type "application/json", the request body is the following:
{
"hdfsLocation" : "hdfs://145.160.10.10:8020"
}
This is the response I get. If I put the parameter in the URL, it works.
{
"httpStatus": 500,
"appErrorId": 0,
"message": "Required String parameter 'hdfsLocation' is not present",
"trackingId": "8c6d45fd-2da5-47ea-a213-3d4ea5764681"
}
Any idea what I am doing wrong?
Thanks,
Serban
Looks like you have confused #RequestBody with #RequestParam. Do either of following :
Pass the request param as a request param(not as a body). Like, (encoded)
http://example.com?hdfsLocation=http%3A%2F%2Fexample.com%3FhdfsLocation%3Dhdfs%3A%2F%2F145.160.10.10%3A8020
Replace the #RequestParam with #RequestBody. If you are sending a body, don't send it along with request param. Those are two different things.
I guess you over looked :)
Shouldn't it be #RequestBody instead of #RequestParam?
Also, even after using #RequestBody, the whole of the JSON string:
{
"hdfsLocation" : "hdfs://145.160.10.10:8020"
}
will be the value of String hdfsLocation and not just the hdfs url. Hence, you'll have to JSON parse that JSON by yourself to get just the hdfs url.
I have a very weird problem in my Spring MVC application. I am writing a login form and POSTing the data via AJAX into a Spring MVC controller that looks like this:
#Controller
public class LoginResourceController {
private static final Logger log = Logger.getLogger (LoginResourceController.class.getName());
#RequestMapping (value="/login", method = RequestMethod.POST)
public String checkAccount (HttpServletRequest httpRequest, HttpServletResponse httpResponse,
#RequestHeader (value = "User-Agent") String retrievedUserAgent,
#RequestParam("username") String username,
#RequestParam("password") String password,
#RequestParam("rememberMe") String rememberMe)
{
//Check username and password in DB, and then if OK,
return "redirect:/login/redirectToMain";
}
#RequestMapping (value = "/login/redirectToMainpage", method = RequestMethod.GET)
public String redirectControllerToMainPage (HttpServletRequest httpRequest, HttpServletResponse httpResponse)
{
return "mainPage";
}
Now, the problem is, I have the client (browser) upon redirect requesting a URL that contains the entire contents of mainPage.jsp in the URL. So it looks like:
https://localhost:8443/<!DOCTYPE html><html><head><meta charset=utf-8 /><title>Page that the subscriber sees after login</title>....
I am quite confounded by this error. Is this some servlet setting in WEB-INF/web.xml or mvc-dispatcher-servlet.xml that I need to change? I am using Spring 3.0.5.
BTW, my redirect works flawlessly for GET method controllers in the same Spring MVC application. (e.g., when I re-load the main page of my application, the redirect to the logged in mainPage.jsp above works flawlessly). Moreover, other GET methods on other jsps work correctly too (example, redirect to /login page via login.jsp via a GET of https://localhost:8443/.
I have checked the following and they didn't help: 1 2.
Try not to put the redirect in the return of the controller. This seems to either cause the full page to be rendered as the ajax response, or a redirect header is filled in with an url with the full contents of the page as a string in the response body.
As a first approach, try to make the request a normal HTTP request instead of ajax, and it should just work.
Alternativelly try to make the return body empty, and return an HTTP status code to the client. Either 200 OKif the account is OK or 401 Unauthorized:
#RequestMapping (value="/login", method = RequestMethod.POST)
public ResponseEntity checkAccount (HttpServletRequest httpRequest, HttpServletResponse httpResponse,
#RequestHeader (value = "User-Agent") String retrievedUserAgent,
#RequestParam("username") String username,
#RequestParam("password") String password,
#RequestParam("rememberMe") String rememberMe)
{
//Check username and password in DB
....
HttpStatus returnCode = null;
if(usernameAndPasswordOK) {
returnCode = HttpStatus.OK;
}
else {
returnCode = HttpStatus.UNAUTHORIZED;
}
return new ResponseEntity(returnCode);
}
And then on the client redirect with Javascript accordingly.
This was a little tricky for me to figure out, and being a web development noob doesn't help here. Anyway, #jhadesdev's answer above pointed me to the issue.
On my client, I do this:
$("#loginForm").submit(function(evt)
{
evt.preventDefault();
if (loginFormInputIsValid ())
{
$.ajax ({
type: "POST",
url: "/login",
data: $(this).serialize(),
success: function (response)
{
window.location = response;
}
});
}
}
which was the issue--you see, setting the window.location=response; caused the client (browser) to request the server for the funky URL above. I have to change my client call (this is where #jhadesdev's response helped) to make sure I don't do something so wrong.
Thanks for your time, #jhadesdev.
I have a SpringMVC web service for uploading files which looks like this:
#RequestMapping(value="/upload.json", method = RequestMethod.POST)
public #ResponseBody Map<String, Object> upload(MultipartHttpServletRequest request) {
// upload the file
}
and everything is dandy. But if one of the consumers posts a non-multipart form, then i get this exception
java.lang.IllegalStateException: Current request is not of type [org.springframework.web.multipart.MultipartHttpServletRequest]
Which makes sense.. however I dont want my end users to see 500 servlet exceptions. I want a friendly error message.
I just tried this (to be like a catchall for other POSTs):
#RequestMapping(value="/upload.json", method = RequestMethod.POST)
public #ResponseBody Map<String, Object> upload2(){
// return friendly msg
}
but I get this error:
java.lang.IllegalStateException: Ambiguous handler methods mapped for HTTP path '/upload.json'
Is there any way to safely handle both multipart and non-multipart POST requests? in one method, or 2 different methods i dont care.
Check if the request is a multipart yourself:
#RequestMapping(value="/upload.json", method = RequestMethod.POST)
public #ResponseBody Map<String, Object> upload(HttpServletRequest request) {
if (request instanceof MultipartHttpServletRequest) {
// process the uploaded file
}
else {
// other logic
}
}