2019独角兽企业重金招聘Python工程师标准>>>

问题介绍:什么是跨域

简单的说即为浏览器限制访问A站点下的js代码对B站点下的url进行ajax请求。比如说,前端域名是www.abc.com,那么在当前环境中运行的js代码,出于安全考虑,访问www.xyz.com域名下的资源,是受到限制的。现代浏览器默认都会基于安全原因而阻止跨域的ajax请求,这是现代浏览器中必备的功能,但是往往给开发带来不便。特别是对我这样后台开发人员来讲,这个事情简直神奇。
但跨域的需求却一直都在,为了跨域,勤劳勇敢的程序猿们想出了许许多多的方法,例如,jsonP、代理文件等等。但这些做法增加了许多不必要的维护成本,而且应用场景也有许多限制,例如jsonP并非XHR,所以jsonP只能使用GET传递参数。更详细的资料可以看这里 Web应用跨域访问解决方案汇总

CORS协议

如今的JS大有一统天下的趋势,浏览器已经成了大多应用最好的安身之所。哪怕在移动端也有各种Hybird方案,在本地文件系统的Web页面,也有需要获取外部数据的需求,而这些需求也必然是跨域的。在寻找跨域解决方案时,发现了最优雅解决方案就是HTML5来带了的“Cross-Origin Resource Sharing”的新特性,来赋予开发者权力决定资源是否允许被跨域访问。
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。
它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
为什么说它优雅呢?
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
解决这个问题的关键就落在了我这个负责后台的程序猿身上。
看看文档也不是什么难事嘛,就是需要在http头中设置Access-Control-Allow-Origin来决定需要允许哪些站点来访问。关于CROS协议更详细内容参考跨域资源共享 CORS 详解

CROS常见header

CORS具有以下常见的header

Access-Control-Allow-Origin: http://kbiao.me  Access-Control-Max-Age: 3628800 Access-Control-Allow-Methods: GET,PUT, DELETE Access-Control-Allow-Headers: content-type

"Access-Control-Allow-Origin"表明它允许" http://kbiao.me "发起跨域请求

"Access-Control-Max-Age"表明在3628800秒内,不需要再发送预检验请求,可以缓存该结果(上面的资料上我们知道CROS协议中,一个AJAX请求被分成了第一步的OPTION预检测请求和正式请求)

"Access-Control-Allow-Methods"表明它允许GET、PUT、DELETE的外域请求

"Access-Control-Allow-Headers"表明它允许跨域请求包含content-type头

常规解决方案

知道了问题的原因,也知道了配套的解决办法,现在就让我们来实现解决。思路很简单,当前端要请求跨域资源时候,我们给它加上响应的响应头即可。很显然我们自己定义一个过滤器是最简单不过了。

 /** * Created by kangb on 2016/5/10. */ @Component public class myCORSFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletResponse response = (HttpServletResponse) servletResponse; String origin = (String) servletRequest.getRemoteHost()+":"+servletRequest.getRemotePort(); 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,Authorization"); response.setHeader("Access-Control-Allow-Credentials","true"); filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { } }

@Component 是Spring的注解,关键部分在doFilter中,添加了我们需要的头,option是预检测需要所以需要允许,Authorization是做了oauth2登录响应所必须的,Access-Control-Allow-Credentials表示允许cookies。都是根据自己项目的实际需要配置。
再配置Web.xml使得过滤器生效

<filter> <filter-name>cors</filter-name> <filter-class>·CLASS_PATH·.myeCORSFilter</filter-class> </filter> <filter-mapping> <filter-name>cors</filter-name> <url-pattern>/api/*</url-pattern> </filter-mapping>

接下来前端就可以像往常一样使用AJAX请求获得资源了,完全不需要做出什么改变。

SPRING 4中更优雅的办法

SpringMVC4提供了非常方便的实现跨域的方法。在requestMapping中使用注解。
@CrossOrigin(origins = “http://kbiao.me”)
全局实现 .定义类继承WebMvcConfigurerAdapter,设置跨域相关的配置

public class CorsConfigurerAdapter extends WebMvcConfigurerAdapter{ @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/*").allowedOrigins("*"); } }

将该类注入到容器中:

<bean class="com.tmall.wireless.angel.web.config.CorsConfigurerAdapter"></bean>

更详细的内容参考Spring 官方的hello world案例Enabling Cross Origin Requests for a RESTful Web Service

http://spring.io/guides/gs/rest-service-cors/或者使用git下载示例源码

https://github.com/spring-guides/gs-rest-service-cors.git

第二部分

关于跨域问题,主要用的比较多的是cros跨域。

详细介绍请看https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS

但是,在springmvc+angularjs下支持跨域请求时,出现复杂跨域场景(post + json)失败的情况。

开始的跨域配置如下:

public class CrossInterceptor extends HandlerInterceptorAdapter {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {response.addHeader("Access-Control-Allow-Origin","*");response.addHeader("Access-Control-Allow-Methods","*");response.addHeader("Access-Control-Max-Age","100");response.addHeader("Access-Control-Allow-Headers", "Content-Type");response.addHeader("Access-Control-Allow-Credentials","false");return super.preHandle(request, response, handler);}}

spring-dispatcher-servlet.xml中配置如下:

<mvc:interceptors><mvc:interceptor><mvc:mapping path="/**/*"/><bean class="cn.***.filter.CrossInterceptor" /></mvc:interceptor>
</mvc:interceptors>

针对简单跨域没问题。但是针对post+json请求却失败,提示跨域失败。

跟踪springmvc源码到FrameworkServlet中的doOption方法,发现,接受了option预检,但是spring主动返回allow,没有支持跨域的配置。

因此,加入新的配置如下:

public class CrossFilter extends OncePerRequestFilter {@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {if (request.getHeader("Access-Control-Request-Method") != null && "OPTIONS".equals(request.getMethod())) {// CORS "pre-flight" requestresponse.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);}
}

web.xml配置如下:

<filter><filter-name>cors</filter-name><filter-class>cn.***.filter.CrossFilter</filter-class>
</filter>
<filter-mapping><filter-name>cors</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>

此时,option请求被CrossFilter过滤器接入并赋予跨域响应头,同时也进入FrameworkServlet中的doOption方法。查看浏览器控制台,发现option请求返回支持跨域信息,后续的post请求进入controller。

  • springMVC 4.X跨域

升级spring版本的后,上述跨域并不支持所有浏览器。经测试,Safari正常,chrome异常。重新翻了一下最新的文档后,得到最新的跨域配置如下:

<mvc:cors><mvc:mapping path="/**" allowed-origins="*" allow-credentials="true" max-age="1800" allowed-methods="GET,POST,OPTIONS"/></mvc:cors>

相比3.x系列,简单了很多。

项目中使用的拦截器,配置如下:

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

import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.ztb.context.WebContext;

public class CrossInterceptor extends HandlerInterceptorAdapter {

@Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        response.addHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
        response.addHeader("Access-Control-Allow-Methods", "POST, GET, DELETE, PUT");

response.addHeader("Access-Control-Allow-Headers", "Content-Type");
        response.addHeader("Access-Control-Allow-Credentials", "true");
      (1)  WebContext.getServletResponse().setHeader("Access-Control-Allow-Credentials", "true"); // 是否支持cookie跨域
        return super.preHandle(request, response, handler);
    }
}

注释

(1)中使用的方法

public static HttpServletResponse getServletResponse() {

return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
    }

pring.xml中配置如下:
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**/*"/>
        <bean class="com.**.filter.CrossInterceptor" />
    </mvc:interceptor>
</mvc:interceptors>

转载于:https://my.oschina.net/maojindaoGG/blog/1616121

springmvc【问题1】跨域相关推荐

  1. 使用SpringMVC解决Ajax跨域问题

    使用SpringMVC解决Ajax跨域问题 参考文章: (1)使用SpringMVC解决Ajax跨域问题 (2)https://www.cnblogs.com/mengyao/p/6294787.ht ...

  2. SpringMvc 3.x跨域+ajax请求

    一.Cors,实现Js跨域访问Tomcat下资源(步骤如下) web.xml配置 <filter> <filter-name>CorsFilter</filter-nam ...

  3. 最全面的SpringMVC教程(三)——跨域问题

    前言 本文为 [SpringMVC教程]跨域问题 相关内容介绍.当一个请求url的协议.域名.端口三者之间任意一个与当前页面url不同时,就会产生跨域.那么究竟什么是跨域,跨域问题该如何解决,本文具体 ...

  4. nginx解决浏览器跨域问题_前端通过Nginx反向代理解决跨域问题

    在前面写的一篇文章SpringMVC解决跨域问题,我们探讨了什么是跨域问题以及SpringMVC怎么解决跨域问题,解决方式主要有如下三种方式: JSONP CORS WebSocket 可是这几种方式 ...

  5. CrossOrigin注解的方式实现接口的跨域访问

    springMVC接口实现跨域访问: springMVC框架通过@CrossOrigin注解的方式实现接口的跨域访问 java示例代码: package com.jmst.httpservice; i ...

  6. ajax跨域请求时 会出现什么问题,在用AJAX跨域请求时遇到的问题

    刚刚接触ajax就遇到一个词--跨域. 在我百度了各种资料以后总结了一句话:"只要不是在一个协议.域.名端口下,都属于跨域(127.0.0.1本地也属于跨域)". 在做ajax请求 ...

  7. 前后端分离后产生的跨域问题sessionid丢失,cookies无法写入等

    文章目录 前言 一.会话机制 1. 何为一次会话,会话从什么时候开始,从什么时候结束? 2.cookies如何保持会话,它的工作流程? 3.session原理分析: 实例记录sessionid变化(前 ...

  8. SpringMvc+ajax实现文件跨域上传

    最近开始学习SpringMVC框架,在学习数据绑定的时候,发现可以使用@RequestParam注解绑定请求数据,实现了文件上传.但是如果一个项目是前后端分离的,前端系统向后端服务上传文件该怎么解决了 ...

  9. 【SpringMVC】与权限拦截器冲突导致的Cors跨域设置失效问题

    问题描述 前端域名FE.com向后端域名BE.com分别请求访问优惠券的列表和提交新增的优惠券,API设计所用的Method分别为Get和Post,结果为前一次访问成功而后一次访问失败.这两次请求都是 ...

最新文章

  1. ZooKeeper 如何保证数据一致性
  2. 身为初学Java的你,这些IDE的优缺点你都知道吗?
  3. java 7个数排序_JAVA基础(7)-数组的排序
  4. Oracle常见操作和命令
  5. vue-router学习第一天
  6. 友链导航源码php,2020优化版导航源码自动收录秘趣导航批量检查友链有效性导航源码...
  7. 林淮川孙玄:分布式锁选型背后的架构设计思维【附源码】
  8. HTMLParser错误解决
  9. 鼠标光标变成方块怎么办
  10. python归一化 增大差异_python-面向对象进阶
  11. CSS中已经定义宽度的样式 英文不执行换行
  12. springboot+网络空间安全实验教学中心门户网站 毕业设计-附源码191220
  13. 最优解问题——PuLP解决线性规划问题(一)
  14. 新机安装指南(软件推荐)
  15. node.js -- 手把手教你搭建 电商平台
  16. Android记账本APP开发进阶版
  17. NDK开发QQ语音变声
  18. 计算机管理的磁盘管理简单卷,小编教你磁盘管理新建简单卷怎么做
  19. 《等着我吧,我会回来》 苏·西蒙诺夫
  20. multisim 高低电平点亮灯证明

热门文章

  1. python数据类型详解
  2. SourceTree的安装
  3. Senparc.Weixin.MP SDK 微信公众平台开发教程(十一):高级接口说明
  4. 如何破解root以及grub密码
  5. 外媒列10大理由建议消费者不购买iPad
  6. 匿名块 块内实体的修改
  7. 小爱童鞋@你,一起来撸个小程序吧
  8. Canvas VS . SVG
  9. 获取某一目录之下所有文件的大小
  10. 第二课_课后习题解答