1、什么是跨域
因为浏览器有一个同源策略(SOP),当不同的域名端口、协议的项目内去请求其他项目的接口,要把结果直接显示在浏览器页面的时候,这个时候浏览器因为同源策略SOP,这个时候会拒绝解析请求的结果同时报错405.(注意:这个时候是可以拿到请求的结果的,但是不能显示结果),这就是跨域的问题。为了解决跨域的问题,制定了一个标准,CROS(允许跨域)。
2、跨域问题的解决方案
第一:jsonp
缺点:只能使用get请求
a项目前端代码:
<script type="text/javascript" src="http://www.itmayiedu.com/static/common/jquery-1.7.2.min.js?t=2017-07-27"></script> <script type="text/javascript"> $(document).ready(function() { $.ajax({ type : "GET", async : false, url : "http://b.itmayiedu.com:8081/ajaxB", dataType : "jsonp", jsonp : "jsonpCallback",//服务端用于接收callback调用的function名的参数 success : function(data) { alert(data["errorCode"]); }, error : function() { alert('fail'); } });
}); </script> |
b项目后端代码
@RequestMapping(value = "/ajaxB", method = RequestMethod.GET) public void ajaxB(HttpServletResponse response, String jsonpCallback) throws IOException { JSONObject root = new JSONObject(); root.put("errorCode", "200"); root.put("errorMsg", "登陆成功"); response.setHeader("Content-type", "text/html;charset=UTF-8"); PrintWriter writer = response.getWriter(); writer.print(jsonpCallback + "(" + root.toString() + ")"); writer.close(); } |
第二:使用HTTPclient转发
a项目的页面先访问a项目的转发接口,a项目的转发接口再真正请求b项目的请求接口,请求的接口返回数据,这样做就间接是a项目的页面访问拿到b项目的请求接口的返回结果给浏览器。
缺点:太麻烦,这样每次请求都需要写转发接口,效率比较低
a项目的页面
<script type="text/javascript" src="http://www.itmayiedu.com/static/common/jquery-1.7.2.min.js?t=2017-07-27"></script> <script type="text/javascript"> $(document).ready(function() { $.ajax({ type : "POST", async : false, url : "http://a.itmayiedu.com:8080/forwardB", dataType : "json", success : function(data) { alert(data["errorCode"]); }, error : function() { alert('fail'); } });
}); </script> |
a项目的转发接口
@RequestMapping("/forwardB") @ResponseBody public JSONObject forwardB() { JSONObject result = HttpClientUtils.httpGet("http://b.itmayiedu.com:8081/ajaxB"); System.out.println("result:" + result); return result; } |
b项目真正的请求接口
@RequestMapping("/ajaxB") public Map<String, Object> ajaxB(HttpServletResponse response) { response.setHeader("Access-Control-Allow-Origin", "*"); Map<String, Object> result = new HashMap<String, Object>(); result.put("errorCode", "200"); result.put("errorMsg", "登陆成功"); return result; } |
第三:设置请求头响应跨域,实现 webMVCAdapter接口,重写允许跨域的方法
响应头中设置 response.setHeader("Access-Control-Allow-Origin", "*"),为单个接口设置允许跨域;也可以一整个springboot项目实现webMVCAdapter接口,重写里面关于跨域的方法允许所有的接口跨域。
@RequestMapping("/ajaxB") public Map<String, Object> ajaxB(HttpServletResponse response) { response.setHeader("Access-Control-Allow-Origin", "*"); Map<String, Object> result = new HashMap<String, Object>(); result.put("errorCode", "200"); result.put("errorMsg", "登陆成功"); return result; } |
实现webnmvcconfigadapter接口,为整个项目所有接口允许跨域
|
第四:使用nginx搭建网关允许跨域
使用nginx搭建网关允许跨域的原理是:把不同的项目用同一个域名进行访问,一不同的路径来区分不同的项目,在nginx中配置拦截配置,从而各个项目之间的域名、端口号都一样,这样就不会出现跨域的问题。
nginx相关配置
server { listen 80; server_name www.itmayiedu.com;
###A项目 location /a { proxy_pass http://a.itmayiedu.com:8080/; index index.html index.htm; } ###B项目 location /b { proxy_pass http://b.itmayiedu.com:8081/; index index.html index.htm; } } |
a项目前端代码
<script type="text/javascript" src="http://code.jquery.com/jquery-1.8.0.min.js"></script> <script type="text/javascript"> $(document).ready(function() { $.ajax({ type : "POST", async : false, url : "http://www.itmayiedu.com/b/ajaxB", dataType : "json", success : function(data) { alert(data["errorCode"]); }, error : function() { alert('fail'); } });
}); </script> |
b项目后端代码
@RequestMapping("/ajaxB") public Map<String, Object> ajaxB(HttpServletResponse response) { response.setHeader("Access-Control-Allow-Origin", "*"); Map<String, Object> result = new HashMap<String, Object>(); result.put("errorCode", "200"); result.put("errorMsg", "登陆成功"); return result; } |
第五:使用springcloud gateway网关跨域
springcloud解决跨域的问题就是利用网关的转发,统一访问网关的端口,根据访问路径由网关转发到各个不同的服务
第六:前后端分离的项目,使用node服务器转发允许跨域
前端使用vue,那么在vue项目中新建vue.config.js文件设置跨域
let proxyObj = {}; proxyObj['/ws'] = { ws: true, target: "ws://localhost:8081" }; //拦截http请求 proxyObj['/'] = { ws: false, //webscoket关掉 target: 'http://localhost:8081', //你要把拦截到转化到哪里去 changeOrigin: true, //是否需要跨域 pathRewrite: { //是否需要重写拦截到的地址 '^/': '' } } module.exports = { devServer: { //前端服务本身的信息 host: 'localhost', //前端服务的域名 port: 8080, //前端服务的端口 proxy: proxyObj //前端服务的代理对象 } } |
文章参考:蚂蚁课堂