是两个项目之间使用ajax(前端类似与后端技术httpclient)实现通讯,如果浏览器访问的域名地址和端口号与ajax访问的地址和端口号不一致的情况下,默认情况下浏览器会有安全机制,这个机制就是跨域问题,会造成无法获取到返回结果(但实际还是可以访问的,请求状态码为200,但无法获取到结果)。
跨域问题有如下5中解决方案:
1、使用jsonp解决 跨域问题(不推荐,因为只能支持get请求,不支持post请求)
2、使用httpclient进行转发(不推荐,因为效率非常低,会发送两次请求)
3、设置响应头允许跨域(可以推荐)适合于小公司快速解决问题
4、使用Nginx搭建API接口网关(强烈推荐)因为保证域名和端口都一致,以项目区分反向代理到真实服务器地址。
5、使用Zuul微服务搭建API接口网关(强烈推荐)SpringCloud
网站跨域问题演示:
新建两个maven项目(xwhy_web_a,xwhy_web_b),pom类型为war类型。
pom依赖
org.springframework.boot
spring-boot-starter-parent
2.0.0.RELEASE
org.projectlombok
lombok
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-tomcat
org.apache.tomcat.embed
tomcat-embed-jasper
org.springframework.boot
spring-boot-starter-log4j
1.3.8.RELEASE
org.springframework.boot
spring-boot-starter-aop
org.apache.httpcomponents
httpclient
com.alibaba
fastjson
1.2.47
application.yml (a项目端口号为8080,b项目端口号为8081)
server:
port: 8080
spring:
mvc:
view:
prefix: /WEB-INF/jsp/
suffix: .jsp
在b项目中新建BIndexController.java类
@RestController
@SpringBootApplication
public class BIndexController {
// 该接口提供给A项目进行ajax调用
@RequestMapping("/getBInfo")
public Map getBInfo() {
Map result = new HashMap();
result.put("retCode", "200");
result.put("retMsg", "登陆成功");
return result;
}
public static void main(String[] args) {
SpringApplication.run(BIndexController.class, args);
}
}
在a项目中新建AIndexController.java类
@Controller
@SpringBootApplication
public class AIndexController {
@RequestMapping("/aIndexJsp")
public String aIndexJsp() {
return "aIndexJsp";
}
public static void main(String[] args) {
SpringApplication.run(AIndexController.class, args);
}
}
在a项目中新建aIndexJsp.jsp文件
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
Insert title here
我是A项目,正在调用B项目
在hosts文件最下面加上如下代码:
127.0.0.1 a.itmayiedu.com
127.0.0.1 b.itmayiedu.com
启动两个项目,访问如下地址:a.itmayiedu.com:8080/aIndexJsp,这时候就会可以打开f12可以看到浏览器控制台已经报错了,调用getBInfo调用状态码200,但是没有返回值,这就是跨域问题导致的。
解决方案:
1、设置响应头允许跨域
这种一般都在小项目里面使用,大项目不会使用这种方式
在BIndexController里面进行修改
// 该接口提供给A项目进行ajax调用
@RequestMapping("/getBInfo")
public Map getBInfo(HttpServletResponse response) {
// 告诉客户端(浏览器 )允许跨域访问 *表示所有域名都是可以 在公司中正常的代码应该放入在过滤器中
response.setHeader("Access-Control-Allow-Origin", "*");
Map result = new HashMap();
result.put("retCode", "200");
result.put("retMsg", "登陆成功");
return result;
}
2、使用jsonp方式
原理:使用script发送get请求,将一个参数传过去,然后回调的时候在带回来进行解析.
将aIndexJsp的ajax请求参数进行修改:
BIndexController进行修改:
//使用jsonp 解决跨域问题
@RequestMapping("/getBInfo")
public void getBInfo(HttpServletResponse response, String jsonpCallback) throws IOException {
JSONObject result = new JSONObject();
result.put("retCode", "200");
result.put("retMsg", "登陆成功");
PrintWriter writer = response.getWriter();
writer.println(jsonpCallback + "(" + result.toJSONString() + ")");
writer.close();
}
3、使用httpclient内部转发
优点:安全,因此真实接口调用地址
缺点:两次请求效率低下,代码重复
实现步骤,
1.ajax请求地址还是请求本项目的地址
2.在本项目中我们接受该请求
3.在后端我们使用httpclient进行转发
4.转发之后我们在将获取到请求通过response返回到前端页面
在AIndexController.java类中增加接口:
// 使用HttpClient进行方法B接口
@RequestMapping("/forWardB")
@ResponseBody
public JSONObject forWardB() {
JSONObject result = HttpClientUtils.httpGet("http://b.itmayiedu.com:8081/getBInfo");
return result;
}
在ajax中修改请求地址:
4、使用nginx搭建API接口网关
nginx.conf文件配置
server {
listen 80;
### 拦截域名地址
server_name api.itmayiedu.com;
### 拦截以/a开头的请求
location /a {
### 指定上游服务器负载均衡服务器
proxy_pass http://a.itmayiedu.com:8080;
index index.html index.htm;
}
location /b {
### 指定上游服务器负载均衡服务器
proxy_pass http://b.itmayiedu.com:8081;
index index.html index.htm;
}
}
ajax访问地址修改:
5、使用Zuul搭建API接口网关