- 什么是跨域
-
跨域,指的是从一个域名去请求另外一个域名的资源。即跨域名请求!跨域时,浏览器不能执行其他域名网站的脚本,是由浏览器的同源策略造成的,是浏览器施加的安全限制。
跨域的严格一点来说就是只要协议,域名,端口有任何一个的不同,就被当作是跨域。
- 案例
- 创建2个项目,分别为:
a.basic.com端口号: 8080
b.basic.com端口号: 8081
域名可以在本地的host文件中配置:127.0.0.1 a.basic.com 127.0.0.1 b.basic.com
- 在b.basic.com项目中,创建一个Search.java的controller
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletResponse; /** * Create by wangxb * 2019-08-15 22:58 */ @RestController @RequestMapping("b") public class SearchController { @RequestMapping("/search") public String search(HttpServletResponse response){ // response.setHeader("Access-Control-Allow-Origin", "*"); return "success-search"; } }
- 在a.basic.com项目中,创建一个index页面
注意: 这里a.basic.com的index页面ajax请求的路径是b.basic.com的地址<!doctype html> <html class="x-admin-sm"> <head> <meta charset="UTF-8"> <title>index</title> <script type="text/javascript" src="/jquery-1.7.2.js"></script> </head> <body> <div> <div>管理登录</div> </div> <script> $(function(){ $.ajax({ type:"get", url:"http://b.basic.com:8081/b/search", dataType:"text", success:function(data){ alert(data); }, error:function(){ alert("error"); } }) }) </script> </body> </html>
- 访问效果:
这里浏览器访问的地址是a.basic.com的页面地址,但是页面中的javascript中请求的是b.basic.com的url。这里就存在跨域,
- 解决跨域方案
- 使用设置响应头允许跨域
在b.basic.com项目中设置: response.setHeader("Access-Control-Allow-Origin", "*"); -- '*'表示允许所有,可以指定
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletResponse; /** * Create by wangxb * 2019-08-15 22:58 */ @RestController @RequestMapping("b") public class SearchController { @RequestMapping("/search") public String search(HttpServletResponse response){ response.setHeader("Access-Control-Allow-Origin", "*"); return "success-search"; } }
- 使用jsonp解决
修改a.basic.com的页面的ajax方法
<script> $(function(){ $.ajax({ type:"get", url:"http://b.basic.com:8081/b/search", dataType : "jsonp", jsonp : "jsonpCallback",//服务端用于接收callback调用的function名的参数 success:function(data){ alert(data); }, error:function(){ alert("error"); } }) })
修改b.basic.com的controller
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * Create by wangxb * 2019-08-15 22:58 */ @RestController @RequestMapping("b") public class SearchController { @RequestMapping("/search") public String search(String jsonpCallback) throws Exception{ return jsonpCallback + "(" + 1000 + ")"; } }
缺点:前后端都需要修改,且 jsonp只支持get请求,不支持post - 使用HttpClient技术在服务器内部进行请求
思路: 将ajax请求地址改为本地项目的url(a.basic.com),然后再使用HttpClient请求(b.basic.com)。
相当于发送2次请求, - 使用Nginx搭建API接口网关
思路
使用nginx分别代理a.basic.com:8080和b.basic.com:8081,客户端页面地址和ajax地址都使用nginx地址,作为代理,由nginx进行转发。
步骤:
a、在本地host文件中配置
b、修改a.basic.com页面的ajax请求地址,改为nginx地址127.0.0.1 a.basic.com 127.0.0.1 b.basic.com 127.0.0.1 api.basic.com
c、在nginx.conf配置如下$(function(){ $.ajax({ type:"get", url:"http://api.basic.com/b/search", dataType : "text", success:function(data){ alert(data); }, error:function(){ alert("error"); } }) })
d、测试如下server { listen 80; server_name api.basic.com; location /a { proxy_pass http://a.basic.com:8080; index index.html index.htm; } location /b { proxy_pass http://b.basic.com:8081; index index.html index.htm; } }
浏览器请求的地址是: http://api.basic.com/a/index 由nginx转发到a.basc.com:8080
ajax请求的地址是: http://api.basic.com/b/search 由nginx转发到b.basc.com:8081
- 使用SpringCloud Zuul搭建API接口网关
和nginx原理一样,将请求地址全部使用网关地址,由网关进行转发
创建服务的注册中心,将a.basic和b.basic.com注册到eureka中去,
创建服务网关项目,在application.yml中配置如下:
这里只是个思路,关于springcloud的相关知识,可以参考我的另外一篇文章:SpringCloud基础学习https://blog.csdn.net/xiaobo5264063/article/details/91350355eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ server: port: 8769 spring: application: name: service-zuul zuul: routes: api-a: path: /api-a/** service-id: a.basic.com #表示访问zuul的地址+/api-a/**,就会转发到在eureka注册的服务名位a.basic.com的工程下 api-b: path: /api-b/** #表示访问zuul的地址+/api-b/**,就会转发到在eureka注册的服务名位b.basic.com的工程下 service-id: b.basic.com
- 使用spingcloud第二代网关Gateway解决跨域
基于全集过滤器实现,允许所有请求跨域。import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.http.HttpHeaders; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; @Component public class CrossOriginFilter implements GlobalFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // 允许跨域请求 ServerHttpRequest request = exchange.getRequest(); ServerHttpResponse response = exchange.getResponse(); HttpHeaders headers = response.getHeaders(); headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "*"); headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "POST, GET, PUT, OPTIONS, DELETE, PATCH"); headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true"); headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, "*"); headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*"); return chain.filter(exchange); } }