How do I get the base url of my server with JAX-RS? Basically I want ""http://localhost:8080/.." when the program is on localhost and "http://www.theSite.com/..." when the program is on a live server. I am using Jersey Framework.
Yes, you may use myUri = uri.getBaseUri();
Here how you get the Uri object :
#Path("myresource")
public class MyResource{
#Context
UriInfo uri;
#GET
public String myresponse(){
URI myUri = uri.getBaseUri();
return ...
}
}
You will have plenty of informations with UriInfo. Check here the javadoc.
Use getBaseUri() of #Context UriInfo.
Related
I'm using ReactiveFeignClient from Playtika
I need to use dynamic URL especially for the host part because I want to use the same interface for several services that have the same request and response formats, but different host. The URLs on each service can have different host name and prefix, but all have the same suffix.
For example:
http://localhost:3001/games/purchase
http://localhost:3002/gadgets/phone/purchase
Actually I don't know whether it has the same behavior as non-reactive feign client. I follow the suggestion on How can I change the feign URL during the runtime?.
Here's the client interface.
#ReactiveFeignClient(
name = "dummy",
configuration = TransactionClient.Configuration.class
)
public interface TransactionClient {
// #PostMapping("/purchase") // Using #PostMapping and #RequestLine both don't work
#RequestLine("POST /purchase")
Mono<PurchaseResponseDto> doPurchase(
URI baseUrl,
#Valid #RequestBody PurchaseRequestDto requestDTO
);
#RequiredArgsConstructor
class Configuration {
#Bean
public ReactiveStatusHandler reactiveStatusHandler() {
return new CustomStatusHandler();
}
}
}
And here's the auto configuration
#Configuration
public class TransactionClientServiceAutoConfiguration {
#Bean
public Contract useFeignAnnotations() {
return new Contract.Default();
}
#Bean
#LoadBalanced
public TransactionClient botRemoteClient() {
return Feign.builder().target(Target.EmptyTarget.create(TransactionClient.class));
}
}
However, I got error indicating that no service with name dummy. It's just a dummy name indeed, because the name parameter is required for #ReactiveFeignClient annotation and I want to use the interface for multiple services.
How to make dynamic url possible for #ReactiveFeignClient
From reactive feign github I found this snippet:
IcecreamServiceApi client =
WebReactiveFeign //WebClient based reactive feign
.<IcecreamServiceApi>builder()
.target(IcecreamServiceApi.class, "http://www.myUrl.com")
You can change the url by creating a new instance of the client. Found no other way. Also, I added both #PostMapping and #RequestLine("POST") to the feign interface since I couldn't get the contracts option to work.
Sharing this for posterity or until a better version comes along.
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
Assuming I have a Spring Application whose requests are being authorized with http.authorizeRequests() and #PreAuthorize
Is there a way to get these mappings programmatically?
Is there an api within Spring where I can retrieve which urls are authorized for the currently authenticated user?
I dont know if there are better ways similar to we pass request header like #RequestHeader("Content-Type")... i would love to see that ...
#PreAuthorize("authorizeAccess(#user,#contentType,)")
public Idea somemethod(#RequestBody User user, #RequestHeader("Content-Type") String contentType )
{..}
But below is definitely an option.
Assuming you know how to write overrride or write your own methods to use in spring security (customised class extending SecurityExpressionRoot). If so if you have a method i.e..authorizeAccess
public boolean authorizeAccess(String mapping)
{
// use mapping to authorize
.. do something
}
Then, we can have all urls in a constant file..
package org.somepackage;
public interface URLMappings {
public static String ADMIN = "/admin";
}
Then pass these urls as constants ..
#RequestMapping(value = URLMappings.ADMIN, method = RequestMethod.POST)
#PreAuthorize("authorizeAccess(T(org.somepackage.URLMappings).ADMIN)")
I've faced a problem when I get base URI form uriInfo. Here's a part of code:
#Path("/users")
#POST
public Response createUser(#RequestBody User user, #Context UriInfo uriInfo) {
...
String confirmEmailUrl = uriInfo.getBaseUri().resolve("/users/confirm/" + getConfirmEmailLink(user));
...
}
confirmEmailUrl must be like http://XXX.XXX.XXX.XXX:8080/users/confirm/aergserthserg but I get the following result http://XXX.XXX.XXX.XXX/users/confirm/aergserthserg. The problem within the port. I used in some other methods uriInfo to build the URL and it works correctly. What is wrong here?
I'd like to create URLs based on the URL used by the client for the active request. Is there anything smarter than taking the current HttpServletRequest object and it's getParameter...() methods to rebuilt the complete URL including (and only) it's GET parameters.
Clarification: If possible I want to resign from using a HttpServletRequest object.
Well there are two methods to access this data easier, but the interface doesn't offer the possibility to get the whole URL with one call. You have to build it manually:
public static String makeUrl(HttpServletRequest request)
{
return request.getRequestURL().toString() + "?" + request.getQueryString();
}
I don't know about a way to do this with any Spring MVC facilities.
If you want to access the current Request without passing it everywhere you will have to add a listener in the web.xml:
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
And then use this to get the request bound to the current Thread:
((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest()
Instead of using RequestContextHolder directly, you can also use ServletUriComponentsBuilder and its static methods:
ServletUriComponentsBuilder.fromCurrentContextPath()
ServletUriComponentsBuilder.fromCurrentServletMapping()
ServletUriComponentsBuilder.fromCurrentRequestUri()
ServletUriComponentsBuilder.fromCurrentRequest()
They use RequestContextHolder under the hood, but provide additional flexibility to build new URLs using the capabilities of UriComponentsBuilder.
Example:
ServletUriComponentsBuilder builder = ServletUriComponentsBuilder.fromCurrentRequestUri();
builder.scheme("https");
builder.replaceQueryParam("someBoolean", false);
URI newUri = builder.build().toUri();
Java's URI Class can help you out of this:
public static String getCurrentUrl(HttpServletRequest request){
URL url = new URL(request.getRequestURL().toString());
String host = url.getHost();
String userInfo = url.getUserInfo();
String scheme = url.getProtocol();
String port = url.getPort();
String path = request.getAttribute("javax.servlet.forward.request_uri");
String query = request.getAttribute("javax.servlet.forward.query_string");
URI uri = new URI(scheme,userInfo,host,port,path,query,null)
return uri.toString();
}
in jsp file:
request.getAttribute("javax.servlet.forward.request_uri")
You can also add a UriComponentsBuilder to the method signature of your controller method. Spring will inject an instance of the builder created from the current request.
#GetMapping
public ResponseEntity<MyResponse> doSomething(UriComponentsBuilder uriComponentsBuilder) {
URI someNewUriBasedOnCurrentRequest = uriComponentsBuilder
.replacePath(null)
.replaceQuery(null)
.pathSegment("some", "new", "path")
.build().toUri();
//...
}
Using the builder you can directly start creating URIs based on the current request e.g. modify path segments.
See also UriComponentsBuilderMethodArgumentResolver
If you need the URL till hostname and not the path use Apache's Common Lib StringUtil, and from URL extract the substring till third indexOf /.
public static String getURL(HttpServletRequest request){
String fullURL = request.getRequestURL().toString();
return fullURL.substring(0,StringUtils.ordinalIndexOf(fullURL, "/", 3));
}
Example: If fullURL is https://example.com/path/after/url/ then
Output will be https://example.com
System.out.println(((HttpServletRequest)request).getRequestURI());
I used it. hope it's useful.