POST更改为OPTIONS +对预检请求的响应未通过访问控制检查:否' Access-Control-Allow-Origin'头

时间:2017-01-26 13:42:49

标签: ajax xml soap wsdl cors

  

XMLHttpRequest无法加载http://xxx.xxx。对预检的反应   请求未通过访问控制检查:否   '访问控制允许来源'标题出现在请求的上   资源。起源' null'因此不允许访问。响应   有HTTP状态代码500。

我正在尝试使用ajax发送xml soap,但却给了我这个错误。我尝试了很多选项,但似乎没有任何工作,这里是代码:

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");
                }
            });

我在这里做错了什么?我发送一个POST动作,但它将其视为OPTION。 如何解决这个问题?

我使用Boomerang Rest和Soap Client来测试这项服务,它给了我正确的答案。当我使用我自己的程序时,它给了我XMLHttpRequest无法加载http://xxxxx&#34;错误。我正在使用apache tomcat 6.0并使用Java Web应用程序代码

2 个答案:

答案 0 :(得分:6)

您正在执行该请求的跨域,因此您发出请求的服务器必须发送Access-Control-Allow-Origin响应标头以指示它允许跨源请求。

有关详细信息,请参阅https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS

  

出于安全原因,浏览器会限制从脚本中发起的跨源HTTP请求。例如,XMLHttpRequest和Fetch遵循同源策略。因此,使用XMLHttpRequest或Fetch的Web应用程序只能向其自己的域发出HTTP请求。

OPTIONS请求发生的原因是,当您发送的跨域请求的Content-Type标头的值不是application/x-www-form-urlencodedmultipart/form-data时,或text/plain,您的浏览器首先进行CORS preflight检查。

您的请求发送Content-Type: text/xml; charset="utf-8",因此会导致预检。

就解决方案而言,如果您发送请求的服务器不是您控制并可配置的服务器,则可以使用开放的反向代理,如https://cors-anywhere.herokuapp.com/

它的工作方式是,不是直接将您的请求发送到http://xxx.xxx,而是将其发送到https://cors-anywhere.herokuapp.com/http://xxx.xxx并代理您的请求,并使用Access-Control-Allow-Origin和其他方式响应浏览器预期的CORS标题。

当然,您需要了解如果您的请求包含任何机密信息,如果他们记录请求数据,您将向cors-anywhere.herokuapp.com的维护者公开。

答案 1 :(得分:1)

我的工作是编写一个过滤器,将源作为接受的原点附加到任何选项请求上,并将其添加到需要接受此类请求的任何servlet中。这是我的实施:

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() {
    }
}