I am using Jersey 1.7 and I am trying to access the request body in my method very similar to this question:
How do I read POST parameters for a RESTful service using Jersey?
Body value comes in fine as email=xx#ws.com&password=test1
I tried using #Context HttpServletRequest request and tried to access the email with request.getParameter("email") but get nothing. There is nothing inside request.getparameterMap() either.
My API looks like this:
#POST
#Produces(...)
public Response getData(#FormParam("email") String email, #FormParam("password") String password, String body, #Context HttpServletRequest request) { ....
I tried changing the position of String body and request but to no avail.
The String body gets the value perfectly fine(it is coming from an iPhone device and not through a Form Submit and so shows up in the String body). Right now, I am trying to parse the body content(email=xx#ws.com&password=test1) and get each variable like email out but that is painful.
Is there some way to get the values using request.getParameter("email") ?
Or is there any quick utility to convert the body content into String email and String password ?
TIA,
Vijay
I never used form parameters myself, but the docs say it should work since forever:
#POST
#Consumes("application/x-www-form-urlencoded")
public void post(MultivaluedMap<String, String> formParams) {
// Store the message
}
http://wikis.sun.com/display/Jersey/Overview+of+JAX-RS+1.0+Features
Related
Each request in my app goes through the custom interceptor where it validates the sessionid filed value which is passed as the one of the parameters in the request payload(post method).
If it is url paramter then we can use following snippet to catch the parameter.
Map<String, Object> parameters =
actionInvocation.getInvocationContext().getParameters();
String sessionid = parameters.get("sessionId");
What could be the way to catch this parameter in interceptor if "sessionId" being sent as part request payload.
I tired below code snippet to catch in the interceptor and it is working fine but in later stages in action classes body is not available to read.if we read twice then request body is not available for the second time to read.
public String intercept(ActionInvocation actionInvocation) throws Exception {
Log.debug(getClass().getName(), "intercept", "Debug enter");
ActionContext context = actionInvocation.getInvocationContext();
HttpServletRequest request = (HttpServletRequest) context.get(HTTP_REQUEST);
RestPostBody restBody= new Gson().fromJson(request.getReader(), RestPostBody.class);
}
I'm trying to trasform http GET method call from legacy api server built with MVC1 pattern to new restful api server without any change of front-end source code using netflix zuul and eureka.
I added zuul pre filter transforming legacy url to restful convention url working after PreDecorationFilter and it works fine.
But now I'm facing problem converting the GET method to proper method like POST, PUT, DELETE by distinguising url so that the requests are properly mapped in spring controller via #GetMapping/#PostMapping/#PutMapping/#DeleteMapping.
I looked into SimpleRoutingFilter that handles HttpClient but
Because of environmental constraint, I have to use eureka service id to route to the new api server and that means I should use RibbonRoutingFilter which is quite complicated to find out a right place to this operation in.
So, is this possible to change http method or make new http request before RibbonRoutingFilter?
If possible can you please suggest where is the right place to do that or some reference?
Many thanks!
======================================================================
Milenko Jevremovic,
Would you please tell me more detail about using Feign?
I defiend #FeignClient like below
#PostMapping(value = "{url"}, consumes = "application/json")
ResponseEntity<?> postMethod(#PathVariable("url") String url);
and to get query parameters to request body for POST In zuul pre filter,
after transform logic from GET request url to POST new restful url ...
byte[] bytes = objectMapper.writeValueAsBytes(ctx.get("requestQueryParams"));
ctx.setRequests(new HttpServletRequestWrapper(request) {
#Override ..getMethod
#Override ..getContentLength
#Override ..getConentLengthLong
#Override
public ServletInputStream getInputStream() {
return new ServletInputStreamWrapper(bytes);
}
}
ResponseEntity<?> response feignClient.post(transformedNewApiUri);
and set RequestContext code that you suggested ....
and controller of new api server is like,
#PostMapping
ResponseEntity<model> post(#RequestBody req..)
It comes to controller fine but when I see the http request in post method of controller,
There is no request body for parameters.
(HttpServleterRequest getInputStream shows empty)
The request data set in zuul pre filter by HttpServletRequestWrapper is
not used in Feign maybe...?
Would you please get me more idea setting request body when changing GET query
to POST constructor for using Feign?
It is not possible to change method of HttpServletRequest, but it's possible to replace request in RequestContext. HttpServletRequestWrapper appears to be very helpful:
static class PostHttpServletRequest extends HttpServletRequestWrapper {
public PostHttpServletRequest(HttpServletRequest request) {
super(request);
}
#Override
public String getMethod() {
return "POST";
}
}
So method run can be rewritten as following:
#Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
HttpServletRequest requestWrapper = new PostHttpServletRequest(request);
ctx.setRequest(requestWrapper);
return null;
}
After doing some research did not find any built in solution.
But what comes in my mind you can use Feign client in your Pre filter, get the response, set the response and return it immediately to client from your Pre filter.
You can set Feign client url or your service id, like it is explained in the docs, it uses ribbon as well .
Change response in your run method like:
...
RequestContext ctx = RequestContext.getCurrentContext();
ctx.setResponseStatusCode(your_code);
ctx.setResponseBody(new_body);
ctx.setSendZuulResponse(false);
return null
I am trying to use Spring Social on my application and I noticed while debugging that the original 'OAuth2' state parameter is always null on my app.
See Spring Social source code for org.springframework.social.connect.web.ConnectSupport below:
private void verifyStateParameter(NativeWebRequest request) {
String state = request.getParameter("state");
String originalState = extractCachedOAuth2State(request);//Always null...
if (state == null || !state.equals(originalState)) {
throw new IllegalStateException("The OAuth2 'state' parameter is missing or doesn't match.");
}
}
private String extractCachedOAuth2State(WebRequest request) {
String state = (String) sessionStrategy.getAttribute(request, OAUTH2_STATE_ATTRIBUTE);
sessionStrategy.removeAttribute(request, OAUTH2_STATE_ATTRIBUTE);
return state;
}
Can anyone please help?
edit: I do see the state parameter being passed back by facebook:
Request URL:https://www.facebook.com/v2.5/dialog/oauth?client_id=414113641982912&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fconnect%2Ffacebook&scope=public_profile&state=0b7a97b5-b8d1-4f97-9b60-e3242c9c7eb9
Request Method:GET
Status Code:302
Remote Address:179.60.192.36:443
edit 2: By the way, the exception I get is the following:
Exception while handling OAuth2 callback (The OAuth2 'state' parameter is missing or doesn't match.). Redirecting to facebook connection status page.
It turned out that the issue was caused by the fact that I was relying on headers - as opposed to cookies - to manage the session.
By commenting out the following spring session configuration bean:
#Bean
public HttpSessionStrategy sessionStrategy(){
return new HeaderHttpSessionStrategy();
}
The oauth2 state parameter issue was sorted.
P.S. Now I have got to find a way to get Spring Social to work with my current configuration of Spring Session...
Edit: I managed to keep the HeaderHttpSessionStrategy (on the spring session side) and get it to work by implementing my own SessionStrategy (on the spring social side) as follows:
public class CustomSessionStrategy implements SessionStrategy {
public void setAttribute(RequestAttributes request, String name, Object value) {
request.setAttribute(name, value, RequestAttributes.SCOPE_SESSION);
}
public Object getAttribute(RequestAttributes request, String name) {
ServletWebRequest servletWebRequest = (ServletWebRequest) request;
return servletWebRequest.getParameter(name);
}
public void removeAttribute(RequestAttributes request, String name) {
request.removeAttribute(name, RequestAttributes.SCOPE_SESSION);
}
}
Try this work around and see if that works for you:
To my surprise I opened application in a 'incognito' browser and everything worked. Just like that. I think before something got cached and was causing the issue.
I ran into this issue today, My application was working perfectly fine. I just took a break for few hours and when I ran it again it started complaining about 'The OAuth2 'state' parameter is missing or doesn't match.'
The state param is first put into the session then the request goes out to facebook and the request comes back with the same state param but when spring is looking for session object to get the state param, it is not finding the session. I think it is not finding the session because when the request comes back it thinks that it is a different client (or host), even though the old HttpSession object still exists. The container maintains a HttpSession per client.
What you're getting from Facebook is not a request attribute , it's a request parameter.
You should get it by something like:
request.getParameter("state")
I'm trying to get inputStream from request, but it's always empty. Any idea
how to get the contents of it? I'm trying to make a DataInputStream from it.
Are you uploading multipart requests? The request may have already been processed into a Spring MultipartRequest by Grails in which case you can use getFile() to get the upload contents.
If not, then request.inputStream should work fine.
cheers
Lee
For me it works when I request the controller method with "application/octet-stream" MIME and send some data within the request. Than in the controller I can simply do:
import org.apache.commons.io.IOUtils
def test() {
byte[] requestData = IOUtils.toByteArray(request.getInputStream())
}
That's it :-)
For a POST method, the W3 specs say:
If a resource has been created on the origin server, the response
SHOULD be 201 (Created) and contain an entity which describes the
status of the request and refers to the new resource, and a Location
header (see Section 10.4).
http://www.ietf.org/internet-drafts/draft-ietf-httpbis-p2-semantics-05.txt (section 8.5)
The standard response actually seems to be to send a Redirect to the newly created resource.
I'm building my site with ASP.NET MVC, and tried to follow the spec, so created a ResourceCreatedResult class:
public class ResourceCreatedResult : ActionResult
{
public string Location { get; set; }
public override void ExecuteResult(ControllerContext context)
{
context.HttpContext.Response.Clear();
context.HttpContext.Response.StatusCode = 201;
context.HttpContext.Response.ClearHeaders();
context.HttpContext.Response.AddHeader("Location", Location);
}
}
And my action looks something like this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreateNew(string entityStuff)
{
Entity newEntity = new Entity(entityStuff);
IEntityRepository entityRepository = ObjectFactory.GetInstance<IEntityRepository>();
entityRepository.Add(newEntity);
ActionResult result = new ResourceCreatedResult()
{ Location = Url.Action("Show", new { id = newEntity.Id }) };
return result;
}
However, IE, Firefox and Chrome all fail to redirect to the new resource. Have I messed up generating the correct response, or do web browsers not expect this type of response, instead relying on servers to send a Redirect response?
To be explicit, browsers (including modern browsers like Firefox 3 and IE8) do not "take the hint" and follow up an HTTP 201: Created response with a GET request to the URI supplied in the Location header.
If you want browsers to go to the URI supplied in the Location header, you should send an HTTP 303: See Other status instead.
Redirect after post or post/redirect/get is something your application must do to be user friendly.
Edit. This is above and beyond the HTTP specifications. If we simply return a 201 after a POST, the browser back button behaves badly.
Note that Web Services requests (which do NOT respond to a browser) follow the standard completely and do NOT redirect after post.
It works like this.
The browser POSTS the data.
Your application validates the data. If it's invalid, you respond with the form so they can fix it and POST.
Your application responds with a redirect.
The browser gets the redirect and does a GET.
Your application sees the GET and responds.
Now -- hey presto! -- the back button works.
My solution is to respond with a '201 Created' containing a simple page with a link to the new resource, and a javascript redirect using location.replace().
This lets the same code work for API and browser requests, plays nicely with Back and Refresh buttons, and degrades gracefully in old browsers.
As stated in the spec the response SHOULD be a HTTP 201 with redirect. So it isn't mandatory for a browser vendor to implement the correct answer...
You should try to change to a 30x code to see if it is correctly redirected. If so, it's a browser problem, else it may come from your code (I don't know anything in ASP.NET so I can't "validate" your code)
Shouldn't that only count for when something is "Created" and therefore a simple redirect to action should be genuinely sufficient?