Is there any way to set some header values for spring ModelAndView. The exact issue is the following.
final String confirmationUrl = details.getConfirmationUrl() + details.getOrderAttemptUuid();
final ModelAndView modelAndView = new ModelAndView(new RedirectView(confirmationUrl));
I am creating a new model and view, but would like to set the referer header to some specific value. Is there any way of doing this?
The reason is that when i am comming from https pages and redirecting to https the referer is kept in the request, but when I am comming from https but redirecting to http I lost the referer as per
http://www.w3.org/Protocols/rfc2616/rfc2616-sec15.html#sec15.1.3
Is there any way to keep the referer in the request or set it back to the ModelAndView?
Consider maybe returning a ResponseEntity from your request mapping.
http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/ResponseEntity.html
Then you can set response headers using like this:
#RequestMapping("/handle") public ResponseEntity<String> handle() {
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("MyResponseHeader", "MyValue");
return new ResponseEntity<String>("Hello World", responseHeaders, HttpStatus.CREATED);
}
Could you use the addObject(name, value) method on ModelAndView to store?
http://docs.spring.io/spring/docs/3.2.x/javadoc-api/org/springframework/web/servlet/ModelAndView.html
Related
I am new to web programming in general, especially in Java, so I just learned what a header and body is.
I'm writing RESTful services using Spring MVC. I am able to create simple services with the #RequestMapping in my controllers. I need help understanding how to get HTTP header information from a request that comes to my method in my REST service controller. I would like to parse out the header and get some attributes from it.
Could you explain how I go about getting that information?
When you annotate a parameter with #RequestHeader, the parameter retrieves the header information. So you can just do something like this:
#RequestHeader("Accept")
to get the Accept header.
So from the documentation:
#RequestMapping("/displayHeaderInfo.do")
public void displayHeaderInfo(#RequestHeader("Accept-Encoding") String encoding,
#RequestHeader("Keep-Alive") long keepAlive) {
}
The Accept-Encoding and Keep-Alive header values are provided in the encoding and keepAlive parameters respectively.
And no worries. We are all noobs with something.
You can use the #RequestHeader annotation with HttpHeaders method parameter to gain access to all request headers:
#RequestMapping(value = "/restURL")
public String serveRest(#RequestBody String body, #RequestHeader HttpHeaders headers) {
// Use headers to get the information about all the request headers
long contentLength = headers.getContentLength();
// ...
StreamSource source = new StreamSource(new StringReader(body));
YourObject obj = (YourObject) jaxb2Mashaller.unmarshal(source);
// ...
}
My solution in Header parameters with example is user="test" is:
#RequestMapping(value = "/restURL")
public String serveRest(#RequestBody String body, #RequestHeader HttpHeaders headers){
System.out.println(headers.get("user"));
}
You can use HttpEntity to read both Body and Headers.
#RequestMapping(value = "/restURL")
public String serveRest(HttpEntity<String> httpEntity){
MultiValueMap<String, String> headers =
httpEntity.getHeaders();
Iterator<Map.Entry<String, List<String>>> s =
headers.entrySet().iterator();
while(s.hasNext()) {
Map.Entry<String, List<String>> obj = s.next();
String key = obj.getKey();
List<String> value = obj.getValue();
}
String body = httpEntity.getBody();
}
I'm trying to write a rest endpoint which receives application/x-www-form-urlencoded. But the endpoint does not accept request parameters for #RequestBody or #RequestParam
I Have tried using MultiValueMap to grab the request parameters. But I always get 0 parameters.
Is there a way to get request values to the MultiValueMap or some other POJO class.
AD=&value=sometestvalue - This is the application/x-www-form-urlencoded requestbody. I'm trying to do the request using postman
#RequestMapping(value = "/test/verification/pay/{id}", method = RequestMethod.POST,
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
#ResponseBody
public Response testVerificationPay(#PathVariable("id") long id, #RequestParam MultiValueMap formData,
HttpServletRequest servletRequest, ServiceContext serviceContext){
log.info("!--REQUEST START--!"+formData.toString());
}
You need to use MultiValueMap<String, String>
#RequestMapping(value = "/test/verification/pay/{id}", method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
#ResponseBody
public Response testVerificationPay(#PathVariable("id") long id, #RequestParam MultiValueMap<String, String> formData) {
System.out.println("!--REQUEST START--!" + formData.toString());
return null;
}
You do not use #RequestParam on a POST request as the data is not in the URL as in a GET request.
You should use #RequestBody (doc) along with registering appropriate HttpMessageConverter. Most likely you should use: FormHttpMessageConverter
Try #ResponseBody. Then, change to a String, not a MultiValueMap, to see if the body comes in to the request.
In My controller i have a method below which is working well
#RequestMapping(value="/searchresults",method = RequestMethod.GET)
public SearchResponse searchResults(
#PathVariable("domain") String domain,
#RequestParam(value="rowCount" , defaultValue="0", required=false) Integer rowCount,
HttpServletRequest req){}
but the same thing is not working when adding headers,
#RequestMapping(value="/searchresults", method = RequestMethod.GET,headers = "application/json;charset=UTF-8")
public SearchResponse searchResults(
#PathVariable("domain") String domain,
#RequestParam(value="rowCount" , defaultValue="0", required=false) Integer rowCount,
HttpServletRequest req){}
Exception :
Representation: null org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException: No matching handler method found for servle
t request: path '/search/searchresults.json', method 'GET',
I tried as follows,
#RequestMapping(value="/searchresults", method = RequestMethod.GET,headers = {"content-type=application/json,charset=UTF-8"})
but it throws,
java.lang.IllegalArgumentException: "charset=UTF-8" does not contain '/'
How to resolve it
You forgot to add the headers names :|
application/json is the Content-Type, while UTF-8 is the Charset.
Take a look at the complete list of HTTP headers.
The correct mapping will then be :
#RequestMapping(value="/searchresults", method = RequestMethod.GET,
headers = {"content-type=application/json,charset=UTF-8"})
That said, it's worth knowing that the ContentType should be specified only for POST and PUT requests.
You need to specify the header name also, which is content-type. Change this:
headers ="application/json;charset=UTF-8"
to
headers = {"content-type=application/json,charset=UTF-8"}
Change headers to produces
#RequestMapping(value="/searchresults", method = RequestMethod.GET,produces = "application/json;charset=UTF-8")
public SearchResponse searchResults(
#PathVariable("domain") String domain,
#RequestParam(value="rowCount" , defaultValue="0", required=false) Integer rowCount,
HttpServletRequest req){}
Ideally you should use #RestController if you are using Spring 4
Use ; instead of ,
#RequestMapping(value="/searchresults", method = RequestMethod.GET,headers = {"content-type=application/json;charset=UTF-8"})
There is a workaround for those who use WebLogic, while maybe other app servers an do the similar, here is what worked for me in weblogic.xml
<wls:charset-params>
<wls:input-charset>
<wls:resource-path>/restful</wls:resource-path>
<wls:java-charset-name>UTF-8</wls:java-charset-name>
</wls:input-charset>
</wls:charset-params>
My Request Mapping annotation looks like this:
#RequestMapping(method = RequestMethod.POST, value = "/echo", produces = "text/plain;charset=UTF-8", headers = "Accept=*/*")
adding
headers = {"content-type=application/json,charset=UTF-8"}
didn't help and I am puzzled why, but I got away somehow. HTH
I found this useful (being stuck with Spring 3.0.x):
#ResponseBody
public ResponseEntity<String> getResponse() {
String body = ...
MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
headers.set("Content-Type", "application/json;charset=UTF-8");
return new ResponseEntity<String>(body, headers, HttpStatus.OK);
}
I need to retrieve resources from my server by sending a GET request with some Authorization headers using RestTemplate.
After going over the docs I noticed that none of the GET methods accepts headers as a parameter, and the only way to send Headers such as accept and Authorization is by using the exchange method.
Since it is a very basic action I am wondering if I am missing something and there another, easier way to do it?
You're not missing anything. RestTemplate#exchange(..) is the appropriate method to use to set request headers.
Here's an example (with POST, but just change that to GET and use the entity you want).
Here's another example.
Note that with a GET, your request entity doesn't have to contain anything (unless your API expects it, but that would go against the HTTP spec). It can be an empty String.
You can use postForObject with an HttpEntity. It would look like this:
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Bearer "+accessToken);
HttpEntity<String> entity = new HttpEntity<String>(requestJson,headers);
String result = restTemplate.postForObject(url, entity, String.class);
In a GET request, you'd usually not send a body (it's allowed, but it doesn't serve any purpose). The way to add headers without wiring the RestTemplate differently is to use the exchange or execute methods directly. The get shorthands don't support header modification.
The asymmetry is a bit weird on a first glance, perhaps this is going to be fixed in future versions of Spring.
Here's a super-simple example with basic authentication, headers, and exception handling...
private HttpHeaders createHttpHeaders(String user, String password)
{
String notEncoded = user + ":" + password;
String encodedAuth = "Basic " + Base64.getEncoder().encodeToString(notEncoded.getBytes());
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.add("Authorization", encodedAuth);
return headers;
}
private void doYourThing()
{
String theUrl = "http://blah.blah.com:8080/rest/api/blah";
RestTemplate restTemplate = new RestTemplate();
try {
HttpHeaders headers = createHttpHeaders("fred","1234");
HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
ResponseEntity<String> response = restTemplate.exchange(theUrl, HttpMethod.GET, entity, String.class);
System.out.println("Result - status ("+ response.getStatusCode() + ") has body: " + response.hasBody());
}
catch (Exception eek) {
System.out.println("** Exception: "+ eek.getMessage());
}
}
These days something like the following will suffice:
HttpHeaders headers = new HttpHeaders();
headers.setBearerAuth(accessToken);
restTemplate.exchange(RequestEntity.get(new URI(url)).headers(headers).build(), returnType);
All of these answers appear to be incomplete and/or kludges. Looking at the RestTemplate interface, it sure looks like it is intended to have a ClientHttpRequestFactory injected into it, and then that requestFactory will be used to create the request, including any customizations of headers, body, and request params.
You either need a universal ClientHttpRequestFactory to inject into a single shared RestTemplate or else you need to get a new template instance via new RestTemplate(myHttpRequestFactory).
Unfortunately, it looks somewhat non-trivial to create such a factory, even when you just want to set a single Authorization header, which is pretty frustrating considering what a common requirement that likely is, but at least it allows easy use if, for example, your Authorization header can be created from data contained in a Spring-Security Authorization object, then you can create a factory that sets the outgoing AuthorizationHeader on every request by doing SecurityContextHolder.getContext().getAuthorization() and then populating the header, with null checks as appropriate. Now all outbound rest calls made with that RestTemplate will have the correct Authorization header.
Without more emphasis placed on the HttpClientFactory mechanism, providing simple-to-overload base classes for common cases like adding a single header to requests, most of the nice convenience methods of RestTemplate end up being a waste of time, since they can only rarely be used.
I'd like to see something simple like this made available
#Configuration
public class MyConfig {
#Bean
public RestTemplate getRestTemplate() {
return new RestTemplate(new AbstractHeaderRewritingHttpClientFactory() {
#Override
public HttpHeaders modifyHeaders(HttpHeaders headers) {
headers.addHeader("Authorization", computeAuthString());
return headers;
}
public String computeAuthString() {
// do something better than this, but you get the idea
return SecurityContextHolder.getContext().getAuthorization().getCredential();
}
});
}
}
At the moment, the interface of the available ClientHttpRequestFactory's are harder to interact with than that. Even better would be an abstract wrapper for existing factory implementations which makes them look like a simpler object like AbstractHeaderRewritingRequestFactory for the purposes of replacing just that one piece of functionality. Right now, they are very general purpose such that even writing those wrappers is a complex piece of research.
A simple solution would be to configure static http headers needed for all calls in the bean configuration of the RestTemplate:
#Configuration
public class RestTemplateConfig {
#Bean
public RestTemplate getRestTemplate(#Value("${did-service.bearer-token}") String bearerToken) {
RestTemplate restTemplate = new RestTemplate();
restTemplate.getInterceptors().add((request, body, clientHttpRequestExecution) -> {
HttpHeaders headers = request.getHeaders();
if (!headers.containsKey("Authorization")) {
String token = bearerToken.toLowerCase().startsWith("bearer") ? bearerToken : "Bearer " + bearerToken;
request.getHeaders().add("Authorization", token);
}
return clientHttpRequestExecution.execute(request, body);
});
return restTemplate;
}
}
I'm using Spring Restful web service & having request body with request header as shown below:
#RequestMapping(value = "/mykey", method = RequestMethod.POST, consumes="applicaton/json")
public ResponseEntity<String> getData(#RequestBody String body, #RequestHeader("Auth") String authorization) {
try {
....
} catch (Exception e) {
....
}
}
I want to pass one more optional request header called "X-MyHeader". How do I specify this optional request header in Spring rest service?
Also, how do I pass this same value in response header??
Thanks!
UPDATE: I just found that I can set required=false in request header, so one issue is resolved. Now, the only issue remaining is how do I set the header in the response??
Use required=false in your #RequestHeader:
#PostMapping("/mykey")
public ResponseEntity<String> getData(
#RequestBody String body,
#RequestHeader(value = "Auth", required = false) String authorization) {}
This question is answered here:
In Spring MVC, how can I set the mime type header when using #ResponseBody
Here is a code sample from: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-ann-httpentity
#RequestMapping("/something")
public ResponseEntity<String> handle(HttpEntity<byte[]> requestEntity) throws UnsupportedEncodingException {
String requestHeader = requestEntity.getHeaders().getFirst("MyRequestHeader");
byte[] requestBody = requestEntity.getBody();
// do something with request header and body
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("MyResponseHeader", "MyValue");
return new ResponseEntity<String>("Hello World", responseHeaders, HttpStatus.CREATED);
}