跨域问题是由浏览器的同源策略限制引起,
浏览器的同源策略是为了保证我们网站的安全。
场景示例:
www.A.com 简称A服务
www.B.com 简称B服务
跨域分两个场景:
场景1.
浏览器打开A服务网站,在A网站所在的浏览器页面内打开B网站的页面(ifram可以做到,没详细了解)
有些html标签是允许跨域的,
1、<img src=xxx>
2、<link href=xxx>
3、<script src=xxx>
这是一种前端页面跨域跨域;
场景2.
浏览器打开A服务的网站,在A网站内因为业务需要,需要用js请求B服务的接口取数据。
这是一种前端请求后端接口跨域
解决办法:
- 前端代理(Angular自带)
- Nginx反向代理
- A服务网关转发
- CORS (后端接口给response的Header设置Access-Control-Allow-Origin)
- JSONP
前端代理:
没有了解
nginx反向代理:
将所有涉及到B请求url都在nginx做代理转发配置,这样前端涉及到B的请求都改为请求nginx,
注意:A服务的所有接口也要由nginx代理,这样就能保证前端所有的请求都是请求nginx这一个地址与端口,当然用的传输层协议就一样了,
A服务网关转发:
如果A服务有网关服务,可以在网关服务配置转发处理,所有关于B服务接口的请求都由A服务的网关转发请求(后端服务之间不存在跨域问题,跨域时浏览器的限制)
CORS
CORS是一个W3C标准,全称是跨域资源共享(Cross-origin resource sharing)
它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
JSONP
JOSNP允许页面接受另一个域的JSON数据,通过在页面增加一个可以从其它域加载带有回调的JSON响应的
模拟使用CORS解决跨域场景:
在csdn网页的控制台里的console里,请求本地启动的后端:fetch('http://localhost:9000/gw/get1')
浏览器console报错:
浏览器network报错:
对于这样的报错,需要后端接口返回 response的Header 添加Access-Control-Allow-Origin
分析:这是一个权限控制,用于授权允许访问当前服务的别的服务的地址,
比如B服务的一个接口允许所有别的服务的js跨域请求这个接口,就设置*;如果只允许A服务的js跨域请求这个接口,就将设置www.A.com,设置这些内容是给浏览器用的,浏览器接受到接口的响应数据之后会判断response的Header里有没有Access-Control-Allow-Origin,以及Access-Control-Allow-Origin的值是什么,如果存在且当前请求满足设置的值就正常接受接口的值,如果 不存在或者设置的值不包含当前请求发起者的域名,则浏览器直接扔掉响应数据。
示例:
response.setHeader("Access-Control-Allow-Origin", "*");//允许所有的源请求
//允许指定的源请求(这里允许),这里设置允许源是csdn,则在csdn控制台请求这个接口可以,在知乎的控制台请求这个接口就不行
response.setHeader("Access-Control-Allow-Origin", "CSDN博客 - 专业IT技术发表平台");
后端代码:
@GetMapping("/get1") public void get1(HttpServletRequest request, HttpServletResponse response) throws IOException { PrintWriter writer = response.getWriter(); writer.write("no cors"); } @GetMapping("/get11") public void get11(HttpServletRequest request, HttpServletResponse response) throws IOException { PrintWriter writer = response.getWriter(); writer.write("cors ok"); response.setHeader("Access-Control-Allow-Origin", "*");//允许所有的源请求 } @GetMapping("/get111") public void get111(HttpServletRequest request, HttpServletResponse response) throws IOException { PrintWriter writer = response.getWriter(); writer.write("cors ok"); //允许指定的源请求,在csdn控制台可以,在知乎的控制台就不行 response.setHeader("Access-Control-Allow-Origin", "https://blog.csdn.net"); }
在浏览器打开csdn,打开控制台的console,执行:fetch('http://localhost:9000/gw/get11',{mode:'cors'})
可以正常请求接口:
后记:在实际业务场景里,如果我们需要访问别的系统的接口,可以让别的系统配置接口放行解决,其实就是别的系统做了一个拦截器,在拦截器里对配置放行接口的response设置Access-Control-Allow-Origin