I am in the context of a Rest API. As I am performing cross domain request, I need to send back the header "Access-Control-Allow-Origin".
I have a controller such:
#Controller
#RequestMapping("/api")
public class PackageManagerRestController {
#RequestMapping(method = RequestMethod.OPTIONS, value = "/test")
public void commonOptions(HttpServletResponse theHttpServletResponse) throws IOException {
theHttpServletResponse.addHeader("Access-Control-Allow-Headers", "origin, content-type, accept, x-requested-with");
theHttpServletResponse.addHeader("Access-Control-Max-Age", "60"); // seconds to cache preflight request --> less OPTIONS traffic
theHttpServletResponse.addHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
theHttpServletResponse.addHeader("Access-Control-Allow-Origin", "*");
}
#RequestMapping(method = RequestMethod.GET, value = "/test")
public void getPtions(HttpServletResponse theHttpServletResponse) throws IOException {
theHttpServletResponse.addHeader("Access-Control-Allow-Headers", "origin, content-type, accept, x-requested-with");
theHttpServletResponse.addHeader("Access-Control-Max-Age", "60"); // seconds to cache preflight request --> less OPTIONS traffic
theHttpServletResponse.addHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
theHttpServletResponse.addHeader("Access-Control-Allow-Origin", "*");
}
}
If I run a test with GET, the result is as expected:
$ curl -i -X GET http://localhost:8081/api/test
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Access-Control-Allow-Headers: origin, content-type, accept, x-requested-with
Access-Control-Max-Age: 60
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Origin: *
Content-Length: 0
Date: Wed, 16 Apr 2014 08:18:38 GMT
However, if I send the request with OPTIONS, the controller never handles the request:
$ curl -i -X OPTIONS http://localhost:8081/api/test
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
Content-Length: 0
Date: Wed, 16 Apr 2014 08:19:56 GMT
Anyone has any clue of why I am receiving this "default response" and why I cannot customize it ?
For default Spring DispatcherServlet supports GET, HEAD, POST, PUT, PATCH and DELETE only; if you want to support TRACE and OPTIONS you have to put "dispatchOptionsRequest" and "dispatchTraceRequest" properties to "true"; check here docs.spring.io/spring/docs/4.0.3.RELEASE/javadoc-api
In order to support OPTIONS too in your web.xml you have to put this:
<init-param>
<param-name>dispatchOptionsRequest</param-name>
<param-value>true</param-value>
</init-param>
By adding it I can handle OPTIONS:
~$ curl -i -X OPTIONS http://localhost:8180/sample/api/test
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Access-Control-Allow-Headers: origin, content-type, accept, x-requested-with
Access-Control-Max-Age: 60
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Origin: *
Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
Content-Length: 0
Date: Wed, 16 Apr 2014 08:44:55 GMT
Angelo
according to the last answer
I resolve my problem
#RequestMapping(value = "/**",method = RequestMethod.OPTIONS)
public String getOption(HttpServletResponse response,Model model)
{
response.setHeader("Access-Control-Allow-Origin","*");
response.setHeader("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE");
return "";
}
and we need to add something to the dispacherservlet
<init-param>
<param-name>dispatchOptionsRequest</param-name>
<param-value>true</param-value>
</init-param>
and this is over
Related
I'm specifically trying to test the case where my application doesn't receive a Content-Length header from the server, so I've set up my code not to include that header, but for some reason Spring is including it anyway with a value of 0:
#RequestMapping(value = "/test", method = RequestMethod.HEAD)
public void headTest(HttpServletRequest request, HttpServletResponse response) {
response.addDateHeader("Date", System.currentTimeMillis());
response.addHeader("Accept-Ranges", "bytes");
response.addHeader("Content-Type", "video/mp4");
}
$ curl -I http://myserver.com:8600/test
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Date: Thu, 28 Jul 2022 01:05:11 GMT
Accept-Ranges: bytes
Content-Type: video/mp4
Content-Length: 0
How can I stop Spring from including this header?
Setting a header to null to effectively remove it from the response works for embedded Tomcat and might work for other servers:
response.setHeader("Content-Length", null);
I want to set cookie in Go:
func rememberMe(w http.ResponseWriter,username string) {
expiration := time.Now().AddDate(0,1,0) // cookie will be stored for 1 month
cookie := http.Cookie{Name: "rememberMe",Value: username,Expires: expiration}
http.SetCookie(w,&cookie)
fmt.Println("Cookie has been set.")
}
The response was quite fine and there was a Set-Cookie filed:
Access-Control-Allow-Headers: Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization
Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE
Access-Control-Allow-Origin: *
Content-Length: 10
Content-Type: text/plain; charset=utf-8
Date: Thu, 20 Sep 2018 12:48:20 GMT
Set-Cookie: rememberMe=buddy; Expires=Sat, 20 Oct 2018 12:48:19 GMT
But when I used Chrome developer tools to check the cookie, there was no cookie. I am confused about this problem.
Thanks for #Peter. The thing is cross-origin.My back end runs at locolhost:8088 and front end runs at localhost:8080. So I did some configuration in both back end and front end. Here's the back end code:
func SetupResponse(w *http.ResponseWriter, r *http.Request) {
(*w).Header().Set("Access-Control-Allow-Origin", "http://localhost:8080")
(*w).Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
(*w).Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
(*w).Header().Set("Access-Control-Allow-Credentials", "true")
}
I use axios in front end:
this.$axios.create({ withCredentials: true })
.get("http://localhost:8088/api/")
.then((response) => {
//....
}).catch((error) => {
console.log(error);
});
when i tried to login from my angular login page. I am getting following. and response saying 'Invalid CORS request'.
Request URL:http://127.0.0.1:8088/myproduct/login
Request Method:OPTIONS
Status Code:403 Forbidden
Remote Address:127.0.0.1:8088
Referrer Policy:no-referrer-when-downgrade
Response Headers
view source
Allow:GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
Cache-Control:no-cache, no-store, must-revalidate
Connection:keep-alive
Content-Length:20
Date:Tue, 16 Jan 2018 09:59:47 GMT
Expires:Thu, 01 Jan 1970 00:00:00 GMT
Pragma:no-cache
Server:WildFly/9
X-Powered-By:Undertow/1
Request Headers
view source
Accept:*/*
Accept-Encoding:gzip, deflate, br
Accept-Language:en-US,en;q=0.9
Access-Control-Request-Headers:content-type
Access-Control-Request-Method:POST
Cache-Control:no-cache
Connection:keep-alive
Host:127.0.0.1:8088
Origin:http://localhost:4200
Pragma:no-cache
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36`enter code here`
Not getting what is the problem (where is the problem)? Please suggest.
You can avoid this by adding an annotation in your service side. Something like this -
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
response.setHeader("Access-Control-Allow-Methods", "POST, GET");
response.setHeader("Access-Control-Allow-Origin", "localhost:4200");
Place #CrossOrigin annotation at the top of the #RequestMapping annotation
like this:
#CrossOrigin(origins = "*")
#ResponseStatus(HttpStatus.OK)
#RequestMapping(value = "postanswer", headers = "Accept=application/json;charset=UTF-8", method = RequestMethod.POST)
public ResponseEntity<AnswerResult> PostAnswer(HttpServletRequest request) throws Exception {
}
I know this question has been asked before, and I've checked every message of Spring MVC with the 406 error message and I am beside myself not knowing how to fix this problem since I've tried just about everything put fourth by these previous answers.
This one web-service takes an email address, and returns back a user object in JSON. I can tell you the unit test works great. And I know we pass the Spring Security, we are executing the servlet ... the only problem now is the JSON output ... I don't get that, I get this error message.
So, to be exact:
Spring Core: 4.2.4.RELEASE
Spring Security: 4.0.3.RELEASE
Jackson Faster XML: 2.6.5 (core, databind, annotations)
2.7.0 doesn't seem to work yet ...
Here is the springmvc-servlet.xml:
<context:annotation-config />
<context:component-scan base-package="com.agmednet.server.controller" />
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="com.agmednet.server.HibernateAwareObjectMapper">
<property name="dateFormat">
<bean class="java.text.SimpleDateFormat">
<constructor-arg type="java.lang.String" value="yyyy-MM-dd HH:mm:ss.SSS"></constructor-arg>
</bean>
</property>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
Here is the controller:
#Controller
#RequestMapping("/users")
public class UserAccountController
{
#Autowired
private UserAccountService userAccountService;
#RequestMapping(value = "/email/{email:.*}", method = RequestMethod.GET)
public #ResponseBody UserAccountEntity getByEmailAddress(#PathVariable("email") String email)
{
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
User user = null;
if (principal instanceof User)
{
user = ((User) principal)
}
UserAccountEntity userAccount = userAccountService.getByEmailAddress(email);
return userAccount;
}
}
As you can see, I have the Accept header setup, I have the #ResponseBody annotation.
I have a SimpleCORSFilter Code on top of this:
#Component
public class SimpleCORSFilter implements Filter
{
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException
{
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with, Content-Type, Accept, If-Modified-Since, openam_token");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig){}
public void destroy(){}
}
As you can see, this accepts my custom header for an "openam_token", but is has
"Accept" and "Content-Type" as well.
I am calling this from a linux box behind a firewall, so I have to SSH into the machine, and execute this curl statement:
curl -v -i -X GET -H "openam_token: AQIC5wM2LY4Sfcxfw-GSBSndg-4DMEyrEqcBgiTE4b4e3aE.*AAJTSQACMDE.*" -H "Content-Type: application/json, text/html" -H "Accept: application/json, text/html" backend.spring.mycompany.net:8080/services/api/users/email/user4252002#mycompany.com
So, here is what I am sending via curl in the request:
* Trying 10.0.4.107...
* Connected to backend.spring.agmednet.net (10.0.4.107) port 8080 (#0)
> GET /services/api/users/email/user4252002#agmednet.com HTTP/1.1
> User-Agent: curl/7.40.0
> Host: backend.spring.agmednet.net:8080
> openam_token: AQIC5wM2LY4Sfcxfw-GSBSndg-4DMEyrEqcBgiTE4b4e3aE.*AAJTSQACMDE.*
> Content-Type: application/json, text/html
> Accept: application/json, text/html
And here is the response:
< HTTP/1.1 406 Not Acceptable
HTTP/1.1 406 Not Acceptable
< Server: Apache-Coyote/1.1
Server: Apache-Coyote/1.1
< Access-Control-Allow-Origin: *
Access-Control-Allow-Origin: *
< Access-Control-Allow-Methods: POST, PUT, GET, OPTIONS, DELETE
Access-Control-Allow-Methods: POST, PUT, GET, OPTIONS, DELETE
< Access-Control-Max-Age: 3600
Access-Control-Max-Age: 3600
< Access-Control-Allow-Headers: x-requested-with, Content-Type, Accept, If-Modified-Since, openam_token
Access-Control-Allow-Headers: x-requested-with, Content-Type, Accept, If-Modified-Since, openam_token
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
Pragma: no-cache
< Expires: 0
Expires: 0
< X-XSS-Protection: 1; mode=block
X-XSS-Protection: 1; mode=block
< X-Frame-Options: DENY
X-Frame-Options: DENY
< X-Content-Type-Options: nosniff
X-Content-Type-Options: nosniff
< Set-Cookie: JSESSIONID=76C4B28DD0B5D88EB9341944BDBCD045; Path=/services/; HttpOnly
Set-Cookie: JSESSIONID=76C4B28DD0B5D88EB9341944BDBCD045; Path=/services/; HttpOnly
< Content-Type: text/html;charset=utf-8
Content-Type: text/html;charset=utf-8
< Content-Language: en
Content-Language: en
< Content-Length: 1110
Content-Length: 1110
< Date: Wed, 20 Jan 2016 14:30:28 GMT
Date: Wed, 20 Jan 2016 14:30:28 GMT
<!DOCTYPE html>
<html><head>
<title>Apache Tomcat/8.0.30 - Error report</title>
</head>
<body>
<h1>HTTP Status 406 - </h1>
<div class="line"></div><p><b>type</b> Status report</p>
<p><b>message</b> <u></u></p>
<p><b>description</b>
<u>The resource identified by this request is only capable of generating
responses with characteristics not acceptable according to the request*
Connection #0 to host backend.spring.agmednet.net left intact
"accept" headers.</u></p>
<hr class="line"><h3>Apache Tomcat/8.0.30</h3></body></html>
Ultimately, this is the error message listed above:
The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request* Connection #0 to host backend.spring.mycompany.net left intact
"accept" headers.
So, I am using #ResponseBody, I am using the latest Jackson 2.x version. I am following all the suggestions from previous questions and I still can't get this to work.
Any help would be much appreciated.
The #EnableWebMVC wasn't the problem, and everything you see in the question is 100% correct. I have two other web-services that worked fine. The problem ultimately was with the curl statement itself:
curl -v -i -X GET -H /
"openam_token: AQIC5wM2LY4Sfcxfw-GSBSndg-4DMEyrEqcBgiTE4b4e3aE.*AAJTSQACMDE.*" /
-H "Content-Type: application/json, text/html" /
-H "Accept: application/json, text/html" /
backend.spring.mycompany.net:8080/services/api/users/email/user4252002#mycompany.com
If you notice, the URL and the path variable is not in quotes.
if you notice, the email address has an # symbol in it, which I found out means something to curl. So, what I did was change my curl to the following.
curl -v -i -X GET -H /
"openam_token: AQIC5wM2LY4Sfcxfw-GSBSndg-4DMEyrEqcBgiTE4b4e3aE.*AAJTSQACMDE.*" /
-H "Content-Type: */*" /
-H "Accept: */*" /
"backend.spring.mycompany.net:8080/services/api/users/email/user4252002%40mycompany%2Ecom"
1) I encoded the email address myself # to %40 and period-dot to %2E
You can use whatever tool you meant to encode the path variable.
2) Even though I am returning a java object transformed into JSON, I changed headers "Accept" and "Content-Type" to "/".
That was it. This worked and the 406 error message went away.
I have a Spring Boot REST application that has a very simple CORS filter on it. What I want to do is dynamically respond to the values in the Access-Control-Request-Headers header, rather than provide a specific list. The common wisdom seems to be the explicitly set the values returned in the "Access-Control-Allow-Headers", however we will be white-listing a set of origins and want to allow any headers they send. I cannot find a way to parrot back the value of Access-Control-Allow-Headers in Access-Control-Request-Headers.
Here's the code
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, DELETE, OPTIONS"); // will need to enable other methods when/as implemented
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers",
((HttpServletRequest) servletRequest).getHeader("Access-Control-Request-Headers"));
filterChain.doFilter(servletRequest, servletResponse);
}
With this request & response from Chrome (when we were hard-coding the value of Access-Control-Allow-Headers)
Remote Address:10.199.240.16:443
Request URL:https://myapp.com/gradebooks/5566669e-e4b0-d05e-0150-98d7ffffffff/assignments/3ad7f1e7-679b-4d8b-856e-d2e3589eaad6
Request Method:OPTIONS
Status Code:200 OK
Response Headers
view source
Access-Control-Allow-Methods → POST, PUT, GET, DELETE, OPTIONS
Access-Control-Max-Age → 3600
Content-Type → application/hal+json; charset=UTF-8
Date → Tue, 21 Jul 2015 20:42:29 GMT
Server → Jetty(9.2.9.v20150224)
Transfer-Encoding → chunked
X-Application-Context → application
Request Headers
view source
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:accept, content-type
Access-Control-Request-Method:PUT
Connection:keep-alive
Host:gbservices-api.dev-prsn.com
Origin:http://localhost:3000
Referer:http://localhost:3000/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.134 Safari/537.36
This is the error
XMLHttpRequest cannot load
https://myapp.com/gradebooks/5566669e-e4b0-d05e-0150-98d7ffffffff/assignments/3ad7f1e7-679b-4d8b-856e-d2e3589eaad6.
Request header field Content-Type is not allowed by
Access-Control-Allow-Headers.
What I've found debugging into the filter is that the Access-Control-Request-Headers, and only that header, is missing by the time it gets to the filter. Misspell the header and it arrives, so it seems that something is intercepting the header and discarding it before it gets to my filter...