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() { } }
0 comments:
Post a Comment