• 前端页面调用Spring boot接口发生的跨域问题


    最近要重构一个基于spring boot的后端API服务,需要再本地测试。在本地测试时,运行在本地的前端页面发送一个ajax请求访问后端API,然后浏览器报错blocked CORS policy。

    Access to XMLHttpRequest at 'http://127.0.0.1:1234/api/' from origin 'http://dev.couchbase.cloud.qiyi.domain' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

    最后的解决方法很简单,只需要在相应的Controller上加一个注解@CrossOrigin就可以了,也可以将注解加到相应的方法上面。

    为什么有些时候调用服务器的接口时没有发生这个报错?

    原因:浏览器发送ajax请求必须是同源的,也就是浏览器访问服务器接口需要考虑同源,而服务器与服务器之间访问接口是不需要考虑同源的。

    (一)同源策略(SOP策略)

    同源策略(Same-Origin-Policy):URL由协议、域名、端口和路径组成,如果两个URL的协议、域名和端口相同,则表示他们同源。相反,只要协议,域名,端口有任何一个的不同,就被当作是跨域。

    浏览器采用同源策略,禁止页面加载或执行与自身来源不同的域的任何文档或脚本,换句话说浏览器禁止的是来自不同源的"document"或脚本。在一个http请求中,http头部Referer或Origin字段标识了当前域名,Host字段标识了此时请求的域名。因此我们在当前的js页面,通过ajax请求第三方的数据,就会出现浏览器的跨域问题。

    (二)跨域解决方法

    1. 使用CORS策略

    CORS策略:跨域资源共享(Corss Origin Resource Sharing)通过服务器增加一个特殊的Header[Access-Control-Allow-Origin]来告知客户端跨域的限制,如果浏览器支持CORS的话,当判断Origin通过的话,就会允许请求。使用这个Header返回被允许请求跨域请求的来源域,例如网站duelist.cn设置了下面的Header

    Access-Control-Allow-Origin: http://smdcn.net

    这样设置之后,通过http://smdcn.net下的页面对于duelist.cn进行ajax请求就会被允许,而其他网站对duelist.cn依旧会被阻拦,通过这种方式网站拥有者可以自己对此进行限制。当然,如果不想限制来源,可以通过来允许任何站点对该资源进行跨域请求

    Access-Control-Allow-Origin: *

    CORS规范中常见的头信息:

    常见的头信息包括:
    
      Request Headers:
    
      Origin、Access-Control-Request-Method、Access-Control-Request-Headers
    
      Response Headers:
    
      1. 允许向该服务器提交请求的URI
    
      Access-Control-Allow-Origin: <origin> | *
    
      2. 浏览器允许访问的服务器的头信息的白名单
    
      Access-Control-Expose-Headers: ..., ...
    
      3. 请求有效期(单位:秒):
    
      Access-Control-Max-Age: <seconds>
    
      4. 允许的请求方法:
    
      Access-Control-Allow-Methods
    
      5. 实际的请求中,可以使用的自定义HTTP请求头
    
      Access-Control-Allow-Headers
    
      6. 告知客户端,当请求XHR的withCredientials属性是true的时候,响应是否可以被得到。(从而使得下一次请求时,上一次的Cookies可以随着请求发送)
    
      Access-Control-Allow-Credentials:

    在传统的Spring MVC中的使用方法:(网上较多资料都是这种方法)

    import java.io.IOException;
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletResponse;
    import org.springframework.stereotype.Component;
    
    @Component
    public class SimpleCORSFilter implements Filter {
    
        public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
            HttpServletResponse response = (HttpServletResponse) res;
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
            response.setHeader("Access-Control-Max-Age", "3600");
            response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
            chain.doFilter(req, res);
        }
    
        public void init(FilterConfig filterConfig) {}
    
        public void destroy() {}
    
    }
    <filter>
          <filter-name>cors</filter-name>
          <filter-class>com.app.filter.SimpleCORSFilter</filter-class>
        </filter>
        <filter-mapping>
          <filter-name>cors</filter-name>
          <url-pattern>/*</url-pattern>
        </filter-mapping>

    在Spring boot中的使用方法就是添加注解@CrossOrigin

    向@RequestMapping注解的Controller方法处添加一个@CrossOrigin注解:

    @RestController
    @RequestMapping("/account")
    public class AccountController {
    
        @CrossOrigin
        @GetMapping("/{id}")
        public Account retrieve(@PathVariable Long id) {
            // ...
        }
    
        @DeleteMapping("/{id}")
        public void remove(@PathVariable Long id) {
            // ...
        }
    }

    为整个controller启用@CrossOrigin:

    @CrossOrigin(origins = "http://domain2.com", maxAge = 3600)
    @RestController
    @RequestMapping("/account")
    public class AccountController {
    
        @GetMapping("/{id}")
        public Account retrieve(@PathVariable Long id) {
            // ...
        }
    
        @DeleteMapping("/{id}")
        public void remove(@PathVariable Long id) {
            // ...
        }
    }

    其中@CrossOrigin中的2个参数:

    origins  : 允许可访问的域列表

    maxAge:准备响应前的缓存持续的最大时间(以秒为单位)。

    2. 使用jsonp

    jsonp解决跨域问题的原理是,浏览器的script标签是不受同源策略限制的,我们可以在script标签中访问任何域名下的资源文件。利用这一特性,用script标签从服务器中请求数据,同时服务器返回一个带有方法和数据的js代码,请求完成,调用本地的js方法,来完成数据的处理。

    不推荐使用jsonp,首先jsonp是一种非官方的方法,而且这种方法只支持GET方法,不如POST方法安全;而且一般前后端分离最通用的方法是返回统一的json格式。

    3. 服务器代理

    这种方式运用的就是服务器的反向代理技术,控制客户端和服务器的访问都从代理服务器经过,比如用nginx作为服务器代理,在nginx上配置客户端和第三方服务的反向代理,这样就可保证客户端、第三方是同源的了,同一个源,都来自代理服务器。

  • 相关阅读:
    secureCRT使用pem私钥
    常用的GoLang包工具
    解决vs code 调试golang时字符串显示不全的问题
    git 常用操作
    go sqlx db.Query需手动释放
    go dlv 调试
    Ambari中superset-hive认证
    HDP3.x hive load data local inpath 设置
    dolphinscheduler-调度
    sourceTree 提交错误
  • 原文地址:https://www.cnblogs.com/jayinnn/p/10149776.html
Copyright © 2020-2023  润新知