SpringCloud-LoadBalancer: How to get Header from Request? - spring-cloud

I'm using SpringCloud-LoadBalancer and want to code a loadBalancer which select instance by header "x-area".Here is the code:
public class CustomLoadBalancer extends RoundRobinLoadBalancer{
...
...
#Override
public Mono<Response<ServiceInstance>> choose(Request request){
DefaultRequestContext requestContext = (DefaultRequestContext) request.getContext();
RequestData clientRequest = (RequestData) requestContext.getClientRequest();
HttpHeaders headers = clientRequest.getFirst("x-area");
.....
}
...
...
}
But the requestContext.getClientRequest() cannot cast to RequestData,and here is the debug info:
TheLoadBalancerRequestFactory$lambda cannot cast to RequestData,But the arg$2 is what I need,how can I get It? or There is another way which can get header?

Related

Micronaut: Test POST request

In my Micronaut app I have a simple REST controller:
public class Response {
private String code;
public Response(String code) {
this.code = code;
}
}
#Controller("/api/test")
public class TestController {
#Post("/")
public Response index() {
return new Response("OK");
}
}
How can I tests this edpoint? I tried using
#MicronautTest
public class TestControllerTest {
#Inject
EmbeddedServer server;
#Inject
#Client("/")
HttpClient client;
#Test
void testResponse() {
String response = client.toBlocking()
.retrieve(HttpRequest.POST("/api/test/")); // FIXME `HttpRequest.POST` requires body
assertEquals("{\"code\": \"OK\"}", response);
}
but HttpRequest.POST requires an additional body argument to be specified. In my case there is no body to be sent. (In the real code it is a request to initialize a new object and thus it has to be POST).
Usually, when you implement a POST action, you expect that there is a body sent with the request. In your example, you don't accept any POST body, but you still need to pass anything in the unit test.
You can instantiate the HttpRequest object in the following way:
HttpRequest.POST("/api/test/", "");
You can't pass null, it has to be some non-null value (like an empty string.)

How to add custom soap header in ASMX web service response

I wrote a simple web service in ASMX and i want to add a custom header in RESPONSE.
below is the code.
public class WebService1 : System.Web.Services.WebService
{
public List<CustomerInfo> VerifyCustomerInfo(string Id, string IdType, Char InquiredParty, IndividualPartyAttributes IndividualPartyAttributes, string NonIndividualName, AccountQuery accountQuery)
{
List<CustomerInfo> ciList = new List<CustomerInfo>();
string replycode = "E9999999";
CustomerInfo customer = new CustomerInfo();
customer.IsBankCustomer = true;
customer.CustomerNumber = "111";
ciList.Add(customer);
// TODO: add code here to send replyCode ("E9999999") as custom header in response XML.
return ciList;
}
}
If you mean SOAP Header then add below attribute on your WebService method:
[SoapHeader("ABC", Direction = SoapHeaderDirection.Out)]
ABC is the custom class.
[XmlRoot("ABC", Namespace = "")]
public class ABC : SoapHeader

How to make the #RestController do not response data as restful? [duplicate]

I have a REST endpoint implemented with Spring MVC #RestController. Sometime, depends on input parameters in my controller I need to send http redirect on client.
Is it possible with Spring MVC #RestController and if so, could you please show an example ?
Add an HttpServletResponse parameter to your Handler Method then call response.sendRedirect("some-url");
Something like:
#RestController
public class FooController {
#RequestMapping("/foo")
void handleFoo(HttpServletResponse response) throws IOException {
response.sendRedirect("some-url");
}
}
To avoid any direct dependency on HttpServletRequest or HttpServletResponse I suggest a "pure Spring" implementation returning a ResponseEntity like this:
HttpHeaders headers = new HttpHeaders();
headers.setLocation(URI.create(newUrl));
return new ResponseEntity<>(headers, HttpStatus.MOVED_PERMANENTLY);
If your method always returns a redirect, use ResponseEntity<Void>, otherwise whatever is returned normally as generic type.
Came across this question and was surprised that no-one mentioned RedirectView. I have just tested it, and you can solve this in a clean 100% spring way with:
#RestController
public class FooController {
#RequestMapping("/foo")
public RedirectView handleFoo() {
return new RedirectView("some-url");
}
}
redirect means http code 302, which means Found in springMVC.
Here is an util method, which could be placed in some kind of BaseController:
protected ResponseEntity found(HttpServletResponse response, String url) throws IOException { // 302, found, redirect,
response.sendRedirect(url);
return null;
}
But sometimes might want to return http code 301 instead, which means moved permanently.
In that case, here is the util method:
protected ResponseEntity movedPermanently(HttpServletResponse response, String url) { // 301, moved permanently,
return ResponseEntity.status(HttpStatus.MOVED_PERMANENTLY).header(HttpHeaders.LOCATION, url).build();
}
As the redirections are usually needed in a not-straightforward path, I think throwing an exception and handling it later is my favourite solution.
Using a ControllerAdvice
#ControllerAdvice
public class RestResponseEntityExceptionHandler
extends ResponseEntityExceptionHandler {
#ExceptionHandler(value = {
NotLoggedInException.class
})
protected ResponseEntity<Object> handleNotLoggedIn(
final NotLoggedInException ex, final WebRequest request
) {
final String bodyOfResponse = ex.getMessage();
final HttpHeaders headers = new HttpHeaders();
headers.add("Location", ex.getRedirectUri());
return handleExceptionInternal(
ex, bodyOfResponse,
headers, HttpStatus.FOUND, request
);
}
}
The exception class in my case:
#Getter
public class NotLoggedInException extends RuntimeException {
private static final long serialVersionUID = -4900004519786666447L;
String redirectUri;
public NotLoggedInException(final String message, final String uri) {
super(message);
redirectUri = uri;
}
}
And I trigger it like this:
if (null == remoteUser)
throw new NotLoggedInException("please log in", LOGIN_URL);
if you #RestController returns an String you can use something like this
return "redirect:/other/controller/";
and this kind of redirect is only for GET request, if you want to use other type of request use HttpServletResponse

JERSEY - Accessing Generic List in Response

Im facing isssue in getting Jersey Generic List in client response. I need to get it as Entity for some reason.
#XmlRootElement(name="list")
#XmlSeeAlso({RESTDomain.class})
public class JAXBContainer<T> {
private List<T> items = new ArrayList<T>();
public JAXBContainer() { }
public JAXBContainer(List<T> items) {
this.items = items;
}
#XmlElementWrapper(name="items")
#XmlAnyElement(lax=true)
public List<T> getItems() {
return items;
}
public void setItems(List<T> items) {
this.items = items;
}
#XmlAttribute
public int getItemsSize() {
return this.items.size();
}
above is my Generic List to the resopnse
#GET
#Produces({MediaType.APPLICATION_XML})
public Response getREST(){
RESTDomain domain = new RESTDomain();
domain.setName("Adams");
domain.setPlace("Zurich");
List<RESTDomain> restDomains = new ArrayList<RESTDomain>();
restDomains.add(domain);
JAXBContainer<RESTDomain> jAXBContainer= new JAXBContainer<RESTDomain>(restDomains);
GenericEntity<JAXBContainer<RESTDomain>> genericEntity = new GenericEntity<JAXBContainer<RESTDomain>>(jAXBContainer){};
return Response.ok(genericEntity).build();
}
Im returning the container with genericEntity. I know with just List inside genericEntity i can get my Entity at my client but the problem is i need to Use my JAXBContainer for some reason.
#Test
public void restGet() throws JAXBException{
ClientConfig cc = new DefaultClientConfig();
client = Client.create(cc);
String baseURI ="http://localhost:3555/SampleREST/rest/sample";
WebResource webResource = client.resource(baseURI);
JAXBContainer<RESTDomain> jAXBContainer= webResource.get(new GenericType<JAXBContainer<RESTDomain>>(){});
System.out.println("response:: "+jAXBContainer.getItemsSize());
}
My problem is im getting the response as JAXBContainer with GenericType as desired but the size of container is 0. What am i missing here? do i have to Use any marshalling and unmarshalling Mechanisms.
But When i request this URI in browser i get the well formed XML, But it fails in client or do we have any other ways to extract entity in client. Thanks in advance
I don't see that you're setting the accept content type anywhere on the client.
Try with: webResource.accept("application/xml")

Pass a parameter to REST web service via URL

I'm creating a small REST web service using Netbeans. This is my code:
private UriInfo context;
private String name;
public GenericResource() {
}
#GET
#Produces("text/html")
public String getHtml() {
//TODO return proper representation object
return "Hello "+ name;
}
#PUT
#Consumes("text/html")
public void putHtml(String name) {
this.name = name;
}
I'm calling the get method ok since when I call http://localhost:8080/RestWebApp/resources/greeting I get "Hello null" but I'm trying to pass a parameter using http://localhost:8080/RestWebApp/resources/greeting?name=Krt_Malta but the PUT method is not being called... Is this the correct way to pass a parameter or am I missing something?
I'm a newbie to Rest bdw, so sry if it's a simple question.
Thanks! :)
Krt_Malta
The second URL is a plain GET request. To pass data to a PUT request you have to pass it using a form. The URL is reserved for GET as far as I know.
If you build the HTTP-header yourself, you must use POST instead of GET:
GET /RestWebApp/resources/greeting?name=Krt_Malta HTTP/1.0
versus
POST /RestWebApp/resources/greeting?name=Krt_Malta HTTP/1.0
If you use a HTML-form, you must set the method-attribute to "PUT":
<form action="/RestWebApp/resources/greeting" method="PUT">
For JAX-RS to mactch a method annotated with #PUT, you need to submit a PUT request. Normal browsers don't do this but cURL or a HTTP client library can be used.
To map a query parameter to a method argument, JAX-RS provides the #QueryParam annotation.
public void putWithQueryParam(#QueryParam("name") String name) {
// do something
}
You can set:
#PUT
#path{/putHtm}
#Consumes("text/html")
public void putHtml(String name) {
this.name = name;
}
and if you use something like google`s Volley library you can do.
GsonRequest<String> asdf = new GsonRequest<String>(ConnectionProperties.happyhourURL + "/putHtm", String.class, yourString!!, true,
new Response.Listener<Chain>() {
#Override
public void onResponse(Chain response) {
}
}, new CustomErrorListener(this));
MyApplication.getInstance().addToRequestQueue(asdf);
and GsonRequest will look like:
public GsonRequest(String url, Class<T> _clazz, T object, boolean needLogin, Listener<T> successListener, Response.ErrorListener errorlistener) {
super(Method.PUT, url, errorlistener);
_headers = new HashMap<String, String>();
this._clazz = _clazz;
this.successListener = successListener;
this.needsLogin = needLogin;
_object = object;
setTimeout();
}