javascript 跨域请求阻塞 Spring REST 服务 + AJAX

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29389031/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 10:27:46  来源:igfitidea点击:

Cross-Origin Request Blocked Spring REST service + AJAX

javajavascripthtmlajaxspring

提问by Muhammad Suleman

Unable to call spring REST service

无法调用 spring REST 服务

My spring service

我的春季服务

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

My AJAX code

我的 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');
  }
});

I am getting following error :(

我收到以下错误:(

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8080/SpringMVC/rest/MAS/authenticate. This can be fixed by moving the resource to the same domain or enabling CORS.

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

i have also tried dataType: "jsonp". its append my body object into URL which make different URL and cannot hit my service URL then and got 404 error.

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

My browser: firefox 36.0.4

我的浏览器:firefox 36.0.4

How i can get rid from this error, any help?

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

回答by Muhammad Suleman

My AJAX call and service were OK. After searching a lot on internet i have found that its server side problem not client side.

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

on server side with Spring we have to implement filter which will allow CORS requests.

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

filter will look like this.

过滤器看起来像这样。

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

}

and in web.xml apply this filter on your service requests like this

并在 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> 

This may help someone else who went through this problem. :)

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

回答by VMAtm

By default the only method allowed is a GET, and you don't allow the POSTon your server side:

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

Access-Control-Allow-Origin: *

This header only enables CORS, but you need to add this:

此标头仅启用 CORS,但您需要添加以下内容:

Access-Control-Allow-Methods: POST, GET

More detailed how-to about the HTTP access control (CORS)on Mozilla project

HTTP access control (CORS)关于 Mozilla 项目的更详细的操作方法

So your code should be something like this:

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

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

Update:

更新

I have re-read the article, and found out some details:

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

A simple cross-site request is one that:

  • Only uses GET, HEAD or POST. If POST is used to send data to the server, the Content-Typeof the data sent to the server with the HTTP POST request is one of application/x-www-form-urlencoded, multipart/form-data, or text/plain.
  • Does not set custom headers with the HTTP Request (such as X-Modified, etc.)

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

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

As you can read in bold, you must set other Content-Typefor your data (currently it is contentType: "application/json; charset=utf-8",) or use the preflight technique described later:

正如您可以用粗体阅读的那样,您必须Content-Type为您的数据设置 other (当前为contentType: "application/json; charset=utf-8",)或使用稍后描述的预检技术:

  • It uses methods other than GET, HEAD or POST. Also, if POST is used to send request data with a Content-Type other than application/x-www-form-urlencoded, multipart/form-data, or text/plain, e.g. if the POST request sends an XML payload to the server using application/xml or text/xml, then the request is preflighted.
  • It sets custom headers in the request(e.g. the request uses a header such as X-PINGOTHER)
  • 它使用 GET、HEAD 或 POST 以外的方法。此外,如果 POST 用于发送内容类型不是 application/x-www-form-urlencoded、multipart/form-data 或 text/plain 的请求数据,例如,如果 POST 请求向服务器发送 XML 有效负载使用 application/xml 或 text/xml,然后预检请求。
  • 它在请求中设置自定义标头(例如,请求使用 X-PINGOTHER 等标头)

So I suggest you either change the contentType or try to work with this header into your request:

因此,我建议您更改 contentType 或尝试将此标头处理到您的请求中:

Access-Control-Request-Headers: X-HEADER_NAME_OF_YOUR_CHOOSE

and this headers into your response:

并将此标头包含在您的回复中:

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

And after that you can try to call your method.

之后,您可以尝试调用您的方法。

回答by Sumit Sundriyal

Following is the solution for cross platform spring boot web service call.

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

Application URL: http://localhost:8080

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

Webservice URL: http://localhost:9090

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

In your spring controller use following annotation

在您的弹簧控制器中使用以下注释

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