FeignClient GET converted into POST - spring-cloud-feign

We have a quite simple FeignClient
#GetMapping("/{id:.+}")
ResponseEntity<Resource> get(
final HttpServletRequest request,
#PathVariable(name = "id") final String id);
We are using thex Hoxton SR 4 spring cloud dependencies and
it uses the spring-cloud-openfeign 2.2.2.RELEASE.
For some reason this GET request is getting converted into a POST
request and we have no idea why.

Changing {id:.+} to {id} fixes the issue.

Related

AngularDart CurrentInstruction

I am trying to update angular2 to latest version. Several of the functions are missing
I would like to know what is the alternate for the following function
final RouteParams _params;
String get routeName => _router.currentInstruction.component.routeName;
How to get routeName from new AngularDart
Not possible to access current component route anymore.
I don't know what you want to do exactly and how you define your routeName, but you probably need to use additionalData of RoutePath or RouteDefinition
class AdditionalRouteData {
final String routeName;
const AdditionalRouteData({this.routeName});
}
final routePath = RoutePath(
path: '/',
additionalData: AdditionalRouteData(routeName: 'Home'),
);
// then get it that way
(router.current.routePath.additionalData as AdditionalRouteData).routeName;
However, if your routeName is dynamic, you must find a new way to access it (without the router, using a service via dependency injection)

Springcloud feign client parse params in wrong way under Hoxton.SR1

Recently, i upgraded the cloud version from Edgware.RELEASE to Hoxton.SR1,and encounter some problems.
here comes the feign client code :
#FeignClient(name = "system-service)
public interface IHelloProxy{
#RequestMapping(value = "/sysinfo/now", method = RequestMethod.GET)
public void hello(#RequestParam String content);
}
when invoked IHelloProxy and pass the one param "content" with "https://www.oschina.net/?a=1&b=2",the feign debug log print:
---> GET http://system-service/sysinfo/now?content=https:%2F%2Fwww.oschina.net%2F%3Fa=1&b=2 HTTP/1.1
and the receiver got two params:“content”,"b".
the expectation should be :
--> GET http://system-service/sysinfo/now?content=https%3A%2F%2Fwww.oschina.net%2F%3Fa%3D1%26b%3D2
and the receiver also got only one param :"content"
I think the problem is at feign client side which do the wrong query map parsing. is that anyway to solve this ?
thanks.
the problem had solved by upgrade the cloud version to Hoxton.SR1 and Boot verion to 2.2.5.
and the issue is from open feign side, can track by for more detail
https://github.com/OpenFeign/feign/issues/1190

Is there a way to change http request method in netflix zuul routing filter?

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

.net MVC Odata endpoint works on POST, but 404s on GET

My question should have a simple answer, but after hours of experimentation and googling, I have nothing so now I'm here.
I am working with .net MVC 5 odata 2.0. I am trying to create a new odata endpoint that works on a get. I've successfully created a few endpoints that work with POST, but I can't seem to get one that works as a GET.
relevant code
WebApiConfig.cs
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Review>("Reviews");
builder.EntitySet<Strategy>("Strategies");
ActionConfiguration ReviewsInStrategy = builder.Entity<Strategy>().Action("ReviewsInStrategy");
ReviewsInStrategy.ReturnsCollectionFromEntitySet<Review>("Reviews");
config.Routes.MapODataServiceRoute("odata", "odata", builder.GetEdmModel());
StrategiesController.cs
[EnableQuery]
public IQueryable<Review> ReviewsInStrategy([FromODataUri] Guid key){
Strategy strategy = db.Strategies.Find(key);
return strategy.Reviews
}
Now I go to fiddler and try a GET to
[myurl]/odata/Strategies(guid'[myguid]')/ReviewsInStrategy
I get a 404 result. But when I change fiddler to a POST (no other change - I don't add accept headers or content types or anything) it works just fine.
How do I make this work with GET?
You need to add a Get-function to your controller:
[EnableQuery]
public SingleResult<Strategies> Get([FromODataUri] Guid key)
{
IQueryable<Strategies> result = db.Strategies.Where(p => p.Id == key);
return SingleResult.Create(result);
}
That way you can use a GET request on the Strategies-resource. If you still want to use a custom action you must add the parameter to your config:
ActionConfiguration ReviewsInStrategy = builder.Entity<Strategy>().Action("ReviewsInStrategy").Returns<Review>().Parameter<Guid>("Key");
[HttpGet]
[ODataRoute("ReviewsInStrategy(Key={key})")]
public IHttpActionResult<Review> ReviewsInStrategy([FromODataUri] Guid key){
Strategy strategy = db.Strategies.Find(key);
return Ok(strategy.Reviews);
}
Not sure if all this works with the complex type Guid. Maybe you need to change it to string and parse it inside the function. Here is a good msdn article about this.

Get body content using HttpServletRequest in Jersey

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

Resources