【问题标题】:Cross-Origin Request Blocked Spring REST service + AJAX跨域请求阻塞 Spring REST 服务 + AJAX
【发布时间】:2015-06-05 23:54:26
【问题描述】:

无法调用spring REST服务

我的春季服务

@RequestMapping(value = "/MAS/authenticate", method = RequestMethod.POST)
public ResponseEntity<Map<String, String>> authenticate(@RequestBody Subject subject) {
    Map<String, String> result = new HashMap<String, String>();
    result.put("result_detail", "Invalid Password");
    result.put("result", "failure");
    HttpHeaders responseHeaders = new HttpHeaders();
    responseHeaders.setContentType(MediaType.APPLICATION_JSON);
    responseHeaders.add("Access-Control-Allow-Origin", "*"); // also added header to allow cross domain request for any domain
    return new ResponseEntity<Map<String, String>>(result, responseHeaders, HttpStatus.OK);
}

我的 AJAX 代码

$.ajax(
{
  crossDomain: true,
  type: "POST",
  contentType: "application/json; charset=utf-8",
  async: false,
  url: "http://localhost:8080/SpringMVC/rest/MAS/authenticate",
  headers: {"Access-Control-Allow-Origin" : "*"},
  data:{},
  dataType: "json", //also tried "jsonp"
  success: function(data, status, jqXHR)
  {
    alert('success');
  },
  error: function(jqXHR, status)
  {
    alert('error');
  }
});

我收到以下错误:(

跨域请求被阻止:同源策略不允许读取位于http://localhost:8080/SpringMVC/rest/MAS/authenticate 的远程资源。这可以通过将资源移动到同一域或启用 CORS 来解决。

我也试过dataType: "jsonp"。它将我的正文对象附加到 URL 中,该 URL 生成不同的 URL,然后无法访问我的服务 URL 并得到 404 错误。

我的浏览器:firefox 36.0.4

我怎样才能摆脱这个错误,有什么帮助吗?

【问题讨论】:

  • 你使用的是哪个服务器?
  • @Halayem Anis:我正在使用 webSphere,但也在 tomcat 上尝试过。两者都出现相同的错误

标签: java javascript html ajax spring


【解决方案1】:

我的 AJAX 调用和服务正常。在互联网上搜索了很多后,我发现它的服务器端问题不是客户端。

在使用 Spring 的服务器端,我们必须实现允许 CORS 请求的过滤器。

过滤器看起来像这样。

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.filter.OncePerRequestFilter;

public class CORSFilter extends OncePerRequestFilter {
    private static final Log LOG = LogFactory.getLog(CORSFilter.class);

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        response.addHeader("Access-Control-Allow-Origin", "*");
        if (request.getHeader("Access-Control-Request-Method") != null && "OPTIONS".equals(request.getMethod())) {
            LOG.trace("Sending Header....");
            // CORS "pre-flight" request
            response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
            // response.addHeader("Access-Control-Allow-Headers", "Authorization");
            response.addHeader("Access-Control-Allow-Headers", "Content-Type");
            response.addHeader("Access-Control-Max-Age", "1");
        }
        filterChain.doFilter(request, response);
    }

}

并在 web.xml 中将此过滤器应用于您的服务请求,如下所示

    <filter>
        <filter-name>cors</filter-name>
        <filter-class>com.test.common.controller.CORSFilter</filter-class> <!-- your package name and filter class -->
    </filter>
    <filter-mapping>
        <filter-name>cors</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping> 

这可能会帮助遇到此问题的其他人。 :)

【讨论】:

    【解决方案2】:

    默认情况下,唯一允许的方法是GET,并且您不允许在服务器端使用POST

    Access-Control-Allow-Origin: *
    

    此标头仅启用 CORS,但您需要添加:

    Access-Control-Allow-Methods: POST, GET
    

    More detailed how-to about the HTTP access control (CORS) Mozilla 项目

    所以你的代码应该是这样的:

    responseHeaders.add("Access-Control-Allow-Methods", "POST, GET"); // also added header to allow POST, GET method to be available
    responseHeaders.add("Access-Control-Allow-Origin", "*"); // also added header to allow cross domain request for any domain
    

    更新

    我重新阅读了这篇文章,发现了一些细节:

    一个简单的跨站点请求是:

    • 仅使用 GET、HEAD 或 POST。 如果使用 POST 将数据发送到 服务器,Content-Type 用 HTTP 发送到服务器的数据 POST 请求是 application/x-www-form-urlencoded 之一, multipart/form-data 或 text/plain。
    • 不设置自定义标题 HTTP 请求(如 X-Modified 等)

    正如你可以看到的粗体,你必须为你的数据设置其他Content-Type(目前是contentType: "application/json; charset=utf-8",)或者使用后面描述的预检技术:

    • 它使用 GET、HEAD 或 POST 以外的方法。此外,如果使用 POST 发送 Content-Type 以外的请求数据 application/x-www-form-urlencoded、multipart/form-data 或 text/plain, 例如如果 POST 请求使用 application/xml 或 text/xml,然后预检请求。
    • 它在请求中设置自定义标头(例如,请求使用标头,例如 X-PINGOTHER)

    所以我建议您更改 contentType 或尝试将此标头用于您的请求:

    Access-Control-Request-Headers: X-HEADER_NAME_OF_YOUR_CHOOSE
    

    这个标题进入你的响应:

    Access-Control-Allow-Methods: POST, GET, OPTIONS
    Access-Control-Allow-Headers: X-HEADER_NAME_OF_YOUR_CHOOSE
    

    然后你可以尝试调用你的方法。

    【讨论】:

    • 在服务中添加了“Access-Control-Allow-Methods”、“POST, GET”,但仍然出现相同的错误:(
    • 更新了答案,尝试阅读原文并尝试他们的解决方案。
    • 非常感谢您的回复,我尝试了您的其他建议,但无法摆脱此错误:(
    【解决方案3】:

    以下是跨平台spring boot web服务调用的解决方案。

    申请网址:http://localhost:8080

    网络服务网址:http://localhost:9090

    在你的 spring 控制器中使用以下注解

    @CrossOrigin(origins = "http://localhost:8080")
    @RequestMapping(value = "/uri", method = RequestMethod.GET)
    public SomeObject someMethod(){
    // your logic will come here
    }
    

    【讨论】:

      猜你喜欢
      • 2012-04-23
      • 2019-01-22
      • 2019-10-09
      • 2021-11-12
      • 2019-11-04
      • 1970-01-01
      • 2017-06-06
      • 2015-01-26
      • 2019-04-14
      相关资源
      最近更新 更多