跨域问题
一、概念
1、跨域:
是指浏览器对于javascript的同源策略的限制。换句话说这个就是同源策略的保护机制。
例如a.cn下面的js不能调用b.cn中的js对象或数据(因为a.cn和b.cn是不同域),所以跨域就出现了。
2、同源策略:
是指在JS的Ajax请求协议、IP/域名、端口这三项与浏览器上的url地址完全相同,则满足同源策略,既不会出现跨域问题。
列举一些跨域请求,如下:
演示:http://study.cn/json/jsonp/jsonp.html | ||
请求地址 | 形式 | 结果 |
http://study.cn/test/a.html | 同一域名,不同文件夹 | 成功 |
http://study.cn/json/jsonp/jsonp.html | 同一域名,统一文件夹 | 成功 |
http:// |
不同域名,文件路径相同 | 失败 |
http://study.cn |
同一域名,不同端口 | 失败 |
|
同一域名,不同协议 | 失败 |
二、突破跨域限制的解决方案
1、 跨域源资源共享(CORS):
CORS即Cross Origin Resource Sharing(跨域源资源共享),通俗说就是我们所熟知的跨域请求。众所周知,在以前,跨域可以采用代理、JSONP等方式,而在Modern浏览器面前,这些终将成为过去式,因为有了CORS。
CORS在最初接触的时候只大概了解到,通过服务器端设置Access-Control-Allow-Origin响应头,即可使指定来源像访问同源接口一样访问跨域接口,最近在使用CORS的时候,由于需要传输自定义Header信息,发现原来CORS的规范定义远不止这些。
CORS可以分成两种:
1、简单请求
HEAD、GET、POST
这类简单请求,只需要一次请求,后端响应的head部分携带一下信息就可以通过
Access-Control-Allow-Origin:*
Access-Control-Allow-Methods: HEAD,GET,POST
Access-Control-Max-Age: 3600
Access-Control-Expose-Headers:Origin, X-Requested-With, Content-Type, Accept
当你需要访问额外的信息时,就需要在 Access-Control-Expose-Headers 这一项当中填写并以逗号进行分隔。
2、复杂请求
PUT,PATCH, DELETE, OPTIONS等
这类复杂的跨域问题,表面上看起来和简单请求使用上差不多,但实际上浏览器发送了不止一个请求。
1、首先,发送的是一种OPTIONS的"预请求",单服务端返回"预回应"结果为通过(告诉前端我是否允许你跨域访问某资源)
2、 然后,发送最终想要发送的跨域资源请求。
预请求实际上是对服务端的一种权限请求的询问,只有当预请求通过,前端才会实际发送最终的请求。
这类复杂请求,需要最少一次以上的请求,后端响应的head部分携带一下信息才可以通过。
Access-Control-Allow-Origin:*
Access-Control-Allow-Methods: PUT,PATCH,DELETE,OPTIONS
Access-Control-Max-Age: 3600
Access-Control-Expose-Headers:Origin, X-Requested-With, Content-Type, Accept
同理,当你需要访问额外的信息时,也需要在 Access-Control-Expose-Headers 这一项当中填写并以逗号进行分隔。Allow-Method中添加options和Expose-Headers添加Origin,都是为了后端正确响应"预请求"的。所以一定注意不要遗漏了,否则必然导致复杂跨域请求不成功。
三、跨域问题解决方案
Spring MVC 4.2版本后提供了完善的跨域解决方案,具体实体方式如下:
1、application.xml 添加如下配置
<?xml version="1.0" encoding="UTF-8"?> <mvc:annotation-driven /> <mvc:cors> |
2、web.xml 添加如下配置,作用是开启OPTIONS请求,因为默认SpringMVC是关闭了OPTIONS请求的。
<!-- springMvc --> <servlet> <servlet-name>springMvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>dispatchOptionsRequest</param-name> <param-value>true</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springMvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> |