Title: OPTIONS Http request is failing with 404 exception while Post request is working fine
Tags: java;spring-boot;rest;spring-mvc;http-options-method
Question: I've a rest endpoint with an optional PathVariable in spring framework.
@PostMapping("/API_PATH/{param1}/{param2}")
public Result getResult(@PathVariable Integer param1,
@PathVariable(required = false) Integer param2, @RequestBody Data data) {
// SOME LOGIC HERE
I've marked param2 Path variable as not required. So it is an optional value. This POST API works fine when I don't send any value to param2. But when the browser tries to access this API, it sends an OPTIONS type of request before sending the actuals POST request. Now if the OPTIONS reqeust doesn't contain the second path variable  (param2) in the URL, it is failing with 404 exception. Is there a way to work around this problem?
Comment: I've configured CORS. And other POST requests are working from browser.

Comment: have you configured your server to handle CORS (Cross-Origin Resource Sharing)? Without CORS Configuration, POST will not work from a browser. However, same POST request will work from Postman/Android even without CORS configuration.

Here is the accepted answer: OPTIONS requests are what we call pre-flight requests in Cross-origin resource sharing (CORS) which checks the safety measures. For the same, you may need to add CORS Configurations
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@EnableWebMvc
public class WebConfig implements Filter,WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
System.out.println("WebConfig; "+request.getRequestURI());
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With,observe");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Expose-Headers", "Authorization");
response.addHeader("Access-Control-Expose-Headers", "responseType");
response.addHeader("Access-Control-Expose-Headers", "observe");
System.out.println("Request Method: "+request.getMethod());
if (!(request.getMethod().equalsIgnoreCase("OPTIONS"))) {
try {
chain.doFilter(req, res);
} catch(Exception e) {
e.printStackTrace();
}
} else {
System.out.println("Pre-flight");
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST,GET,DELETE,PUT");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Access-Control-Expose-Headers"+"Authorization, content-type," +
"USERID"+"ROLE"+
"access-control-request-headers,access-control-request-method,accept,origin,authorization,x-requested-with,responseType,observe");
response.setStatus(HttpServletResponse.SC_OK);
}
Some Other Ways of CORS Configuration
Using CorsRegistry:
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://domain1.com","http://domain2.com");
Using @CrossOrigin:
@CrossOrigin(origins = {"http://domain1.com","http://domain2.com"})
Using application.properties
management.endpoints.web.cors.allowed-origins=http://domain1.com,http://domain2.com

Here is another answer: Your code is specifically for a POST, so there is no handler for an OPTIONS. Spring provides a CrossOrigin annotation that implements the pre-flight CORS handler, have a read here.
Try this:
@CrossOrigin
@PostMapping("/API_PATH/{param1}/{param2}")
public Result getResult(@PathVariable Integer param1,
@PathVariable(required = false) Integer param2, @RequestBody Data data) {
// SOME LOGIC HERE

{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 2, 'CommentCount': 2, 'ContentLicense': 'CC BY-SA 4.0', 'CreationDate': '2019:00:07/01/19', 'FavoriteCount': None, 'PostTypeId': 1, 'Tags': '<java><spring-boot><rest><spring-mvc><http-options-method>', 'Title': 'OPTIONS Http request is failing with 404 exception while Post request is working fine', 'ViewCount': 2561, 'id': 56835272, 'user_AboutMe': '<p>Software Developer</p>\n', 'user_AccountId': 4450802.0, 'user_DisplayName': 'pkgajulapalli', 'user_Reputation': 1044.0, 'user_Views': 181.0, 'user_id': 4608329.0}}