Wednesday, March 1, 2017

Post as Option, Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header

Leave a Comment

XMLHttpRequest cannot load http://xxx.xxx. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access. The response had HTTP status code 500.

I am trying to send a xml soap with ajax but gives me that error. I have tried many option but nothing seems to work, here is the code:

var soapMessage =                 '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsdl="http://xxx.xxx/">'+                 '<soapenv:Header/>'+                 '<soapenv:Body>'+                    '<wsdl:test1>'+                       '<PUI>12345</PUI>'+                    '</wsdl:test1>'+                ' </soapenv:Body>'+              '</soapenv:Envelope>';              $.ajax({                 url: 'http://xxx.xxx',                  type: 'POST',                 dataType: 'xml',                  data: soapMessage,                  crossDomain: true,                 processData: false,                 contentType: 'text/xml; charset=\"utf-8\"',                 headers: {                     SOAPAction: "http://xxx.xxx"                 },                 success: function (msg, data) {                     alert(msg);                  },                 error: function (msg, data) {                     alert("Error");                 }             }); 

what am I doing wrong here? I send a POST action but it read it as OPTION. How to fix this?

I use Boomerang Rest and Soap Client to test this service and it gives me response correctly. When I use my own program as above it gives me XMLHttpRequest cannot load http://xxxxx" error. I am using apache tomcat 6.0 and using a Java web Application for the code

2 Answers

Answers 1

You’re doing that request cross-origin, so the server you’re making the request to must send an Access-Control-Allow-Origin response header to indicate it allows cross-origin requests.

See https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS for more details.

For security reasons, browsers restrict cross-origin HTTP requests initiated from within scripts. For example, XMLHttpRequest and Fetch follow the same-origin policy. So, a web application using XMLHttpRequest or Fetch could only make HTTP requests to its own domain.

And the reason an OPTIONS request happens is that when you send a cross-origin request with a Content-Type header that has a value other than application/x-www-form-urlencoded, multipart/form-data, or text/plain, your browser first does a CORS preflight check.

Your request sends Content-Type: text/xml; charset="utf-8", so that causes a preflight.

As far as workarounds if the server you’re sending the request to is not one that you control and can configure, you can use an open reverse proxy like https://cors-anywhere.herokuapp.com/.

The way it works is that instead of sending your request directly to http://xxx.xxx, you send it instead to https://cors-anywhere.herokuapp.com/http://xxx.xxx and that proxies your request and responds to the browser with Access-Control-Allow-Origin and other expected CORS headers.

Of course you need to understand that if your request contains any confidential information, you’d be exposing it to the maintainers of cors-anywhere.herokuapp.com if they log data for requests.

Answers 2

My work around for this was to write a filter that appends the origin as an accepted origin onto any options request and added it to whatever servlet that would need to accept such requests. Here's my implementation:

public class CorsFilter implements Filter {      private static List<String> validServers = Arrays.asList([you need to fill this in with whatever sites you want to allow access]);      @Override     public void init(FilterConfig filterConfig) throws ServletException {     }      @Override     public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {         if (servletRequest instanceof HttpServletRequest) {             HttpServletRequest request = (HttpServletRequest) servletRequest;             HttpServletResponse response = (HttpServletResponse) servletResponse;             String origin = request.getHeader("Origin");             if (StringUtils.isNotBlank(origin)) { //this is a cors request                 boolean hasPrefix = origin.contains("/");                 boolean hasPort = origin.contains(":");                 String serverAlias = origin.substring(hasPrefix ? origin.lastIndexOf("/") + 1 : 0, hasPort ? origin.lastIndexOf(":") : origin.length());                 if (validServers.contains(serverAlias)) {                     response.setHeader("Access-Control-Allow-Credentials", "true");                     response.setHeader("Access-Control-Allow-Methods", "OPTIONS, POST, GET, PUT, DELETE");                     response.setHeader("Access-Control-Allow-Origin", origin);                     response.setHeader("Access-Control-Allow-Headers", "Content-Type");                     //credentials are not sent on options requests, kick out here so that the access control headers and nothing else can be returned                     if ("OPTIONS".equals(request.getMethod())) {                         response.setStatus(200);                         return;                     }                 } else {                     response.sendError(HttpStatus.SC_FORBIDDEN);                     response.flushBuffer();                     return;                 }             }         }          filterChain.doFilter(servletRequest, servletResponse);     }       @Override     public void destroy() {     } } 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment