跨域相关问题

允许跨域的方式

  1、JSONP,只能发出get请求

    使用<script src="">来完成一个跨域请求:

        当点击"跨域获取数据"的按钮时,添加一个<script>标签,用于发起跨域请求;注意看请求地址后面带了一个callback=showData的参数;

        showData即是回调函数名称,传到后台,用于包裹数据。数据返回到前端后,就是showData(result)的形式,因为是script脚本,所以自动调用showData函数,而result就是showData的参数。

        至此,我们算是跨域把数据请求回来了,但是比较麻烦,需要自己写脚本发起请求,然后写个回调函数处理数据,不是很方便。

    

 1 //回调函数
 2          function showData (result) {
 3              var data = JSON.stringify(result); //json对象转成字符串
 4             $("#text").val(data);
 5          }
 6  
 7          $(document).ready(function () {
 8  
 9              $("#btn").click(function () {
10                 //向头部输入一个脚本,该脚本发起一个跨域请求
11                  $("head").append("<script src='http://localhost:9090/student?callback=showData'></script>");
12              });
13  
14          });

      服务端:

 

 1 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 2      response.setCharacterEncoding("UTF-8");
 3      response.setContentType("text/html;charset=UTF-8");
 4  
 5      //数据
 6      List<Student> studentList = getStudentList();
 7  
 8  
 9      JSONArray jsonArray = JSONArray.fromObject(studentList);
10      String result = jsonArray.toString();
11  
12      //前端传过来的回调函数名称
13      String callback = request.getParameter("callback");
14      //用回调函数名称包裹返回数据,这样,返回数据就作为回调函数的参数传回去了
15      result = callback + "(" + result + ")";
16  
17      response.getWriter().write(result);
18  }

    jquery的jsonp方式跨域请求:

         服务端代码不变,js代码如下:最简单的方式,只需配置一个dataType:'jsonp',就可以发起一个跨域请求。jsonp指定服务器返回的数据类型为jsonp格式,可以看发起的请求路径,自动带了一个callback=xxx,xxx是jquery随机生成的一个回调函数名称。

         这里的success就跟上面的showData一样,如果有success函数则默认success()作为回调函数。

 1 $(document).ready(function () {
 2  
 3              $("#btn").click(function () {
 4  
 5                  $.ajax({
 6                      url: "http://localhost:9090/student",
 7                      type: "GET",
 8                      dataType: "jsonp", //指定服务器返回的数据类型
 9                      success: function (data) {
10                          var result = JSON.stringify(data); //json对象转成字符串
11                          $("#text").val(result);
12                      }
13                  });
14  
15              });
16  
17          });

        指定回调函数至于在上面加上     jsonpCallback: "showData", //指定回调函数名称,但success()方法在调用过指定回调函数后仍会调用。

  2、CORS

      1、在允许跨域访问的方法内设置response,只允许此方法跨域访问

 

1         response.addHeader("Access-Control-Allow-Origin", "*");
2         response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
3         response.addHeader("Access-Control-Allow-Headers", "Content-Type");
4         response.addHeader("Access-Control-Max-Age", "1800");//30 min

       2、在拦截器中配置,配置在项目的web.xml中时,整个项目接口均允许跨域

<filter>
    <filter-name>cros</filter-name>
    <filter-class>cn.ifengkou.test.filter.CORSFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>cros</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
@Component
public class CORSFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        response.addHeader("Access-Control-Allow-Origin", "*");
        response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
        response.addHeader("Access-Control-Allow-Headers", "Content-Type");
        response.addHeader("Access-Control-Max-Age", "1800");//30 min
        filterChain.doFilter(request, response);
    }
}

      3、SpringMVC提供@CrossOrigin注解允许跨域,加载类上表示整个controller都可跨域,用在方法上表示此方法允许跨域

      4、tomcat配置允许跨域

      5、nginx配置允许跨域

#
# Wide-open CORS config for nginx
#
location / {
     if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        #
        # Custom headers and headers various browsers *should* be OK with but aren't
        #
        add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
        #
        # Tell client that this pre-flight info is valid for 20 days
        #
        add_header 'Access-Control-Max-Age' 1728000;
        add_header 'Content-Type' 'text/plain charset=UTF-8';
        add_header 'Content-Length' 0;
        return 204;
     }
     if ($request_method = 'POST') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
     }
     if ($request_method = 'GET') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
     }
}

注意:重定向的跨域访问中 Access-Control-Allow-Origin的值不能设置为‘*’,必须设置为具体的源

shiro中对跨域的支持

  对简单请求支持,非简单请求时需重写 FormAuthenticationFilter中的isAccessAllowed方法

protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        return request instanceof HttpServletRequest && ((HttpServletRequest)request).getMethod().toUpperCase().equals("OPTIONS") ? true : super.isAccessAllowed(request, response, mappedValue);
    }

 

跨域请求时,浏览器会过滤相关响应头中自定义的key,想要不过滤,在服务端响应头中写入不需过滤的key

    response.setHeader("Access-Control-Expose-Headers", "所要展示的key")

原文地址:https://www.cnblogs.com/fg-fd/p/9896765.html