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?
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