前后端分离带来的跨域问题
1、什么同源策略?
同源指的是 "协议 + 域名 + 端口 “ 三个相同,即使两个不同的域名指向同一个IP地址,也是非同源。
同源策略是为了安全,确保一个应用中的资源只能被本应用的资源访问。否则,岂不是谁都能访问。
同源
非同源
两个相同的源之间浏览器是默认可以相互访问资源和操作DOM的。两个不同的源之间
若想要相互访问资源或者操作 DOM,那么会有一套基础的安全策略的制约。具体有如下两
方面的限制。
1. 安全性: 浏览器要防止当前站点的私密数据不会向其他站点发送
如当前站点的Cookie,LocalStorage,IndexDb 不会被发送到其他站点或被其他站点脚本读
取到无法跨域获取Dom,无法发送Ajax请求。
2. 可用性:大型站点的图片,音视频等资源,希望部署在独立服务器上,为缓解当前服务
的压力,开放某些特定的方式,访问非同源站点
前端解决跨域的三种方法,如:<script><img><iframe><link><vedio>等,可以同src属性跨域访问
允许跨域提交表单/或重定向请求
解决方案
1.服务端解决
跨域请求分两种情况
a. 简单请求:
请求方法使用GET/HEAD/POST请求之一
仅能使用CORS安全的头部,Accept,Accept-Language,Content-Language,Content-Type
如果浏览器得到上述响应,则认定为可以跨域,后续就跟简单请求的处理是一样的了。虽然原理比较复杂,但是前面说过:事实上,SpringMVC已经帮我们写好了CORS的跨域过滤器:CorsFilter ,内部已经实现了刚才所讲的判定逻辑,我们直。
Content-Type的值只能是:text/plain,multipart/form-data,application/x-
www-form- urlencoded三者其中之一
站点。
/** * 简单请求1 * * @param response * @return * @throws IOException */@RequestMapping(value = &34;,method = RequestMethod.GET)@ResponseBodypublic String ajaxGetReq(HttpServletResponse response) throws IOException {response.addHeader(&34;,&34;);return &34;;}/** * 简单请求2 * * @param user * @param response * @return * @throws IOException */@RequestMapping(value = &34;,method = RequestMethod.POST)@ResponseBodypublic User ajaxPostReq2(User user,HttpServletResponse response) throws IOException {response.addHeader(&34;,&34;);return user;}
b. 复杂请求
想要彻底解决跨域问题,只需要破坏以上三个条件的任一即可:添加浏览器启动参数: chrome --disable-web-security ,但是极不推荐这种解决方式。Jsonp,全称 JSON with Padding ,一种非官方的协议,而是一种约定;前端通过。
不符合简单请求条件的即为复杂请求,访问跨域资源前,需要发起preflight预检请求
(OPTIONS请求)询问何种请求是被允许的,预检请求失败,则不会发起正式的业务请
求,预检请求成功,然后发起正式请求
3. 在 Controller 注解上方添加 @CrossOrigin 注解后,仍然出现跨域问题,解决方案之一就是:在 @RequestMapping 注解中没有指定 Get、Post 方式,具体指定后,问题解决。类似代码如下:参考文章:1. 官方文档 https://spring。.
SpringBoot解决方案:
1. 创建一个filter解决跨域。
@Componentpublic class SimpleCORSFilter implements Filter {public void doFilter(ServletRequest req,ServletResponse res,FilterChain chain) throws IOException,ServletException {HttpServletResponse response = (HttpServletResponse) res;response.setHeader(&34;,&34;);response.setHeader(&34;,&34;);response.setHeader(&34;,&34;);response.setHeader(&34;,&34;); chain.doFilter(req,res);}public void init(FilterConfig filterConfig) {}public void destroy() {}}
直接在 Nginx 中设置允许跨域的 header(也可以在后端的应用程序内设置,不过在 Nginx 入口配置的话更加统一),在 location 配置中直接使用指令 add_header( 官方文档链接 ),
2.基于WebMvcConfigurerAdapter配置加入Cors的跨域
import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;@Configuration public class CorsConfig extends WebMvcConfigurerAdapter {@Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(&34;) .allowedOrigins(&34;) .allowCredentials(true) .allowedMethods(&34;,&34;,&34;,&34;) .maxAge(3600); } }
如果你想做到更细致也可以使用@CrossOrigin这个注解在controller类中使用。
这样就可以指定该controller中所有方法都能处理来自http:19.168.1.10:8080中的请求。
脚手架提供一个配置好的 webpack ,可以在配置文件中的proxy添加代理地址,这样可以避免跨域问题,如果是自己搭建的框架自行配置 webpack 依然可以实现代理
第一种Filter的方案也支持springmvc。
第二种常用于springboot。
2. 代理服务器,反向代理接口请求
apache http server / nginx
3. jsonp 方式
<script>function clickButton() {var scriptTag = document.createElement(&34;);scriptTag.src = &34;;document.body.appendChild(scriptTag);}function myFunc(myObj) {document.getElementById(&34;).innerHTML = myObj.name;}</script>