前言:最近在做一个前后端分离的项目时,出现了前端无法正确返回JSON数据给后端的问题,在查看浏览器的控制台输出发现是跨域问题导致的,故在此记录一下解决问题的方案。
一、什么是跨域问题
跨域,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript施加的安全限制。
跨域问题:
JavaScript使用ajax请求进行跨地址请求 , 无法返回json数据.
跨域问题来源:
JavaScript的同源保护策略,即只有 协议+主机名+端口号 相同,则允许相互访问。
也就是说JavaScript只能访问和操作自己域下的资源,不能访问和操作其他域下的资源。
一般来说,有以下三种原因会导致跨域问题产生。
- 访问协议,Http 和 Https协议的不同会造成跨域问题。
- 访问地址,192.128.2.1 和 172.11.3.2 IP地址不同,无法访问
- 端口号,访问和请求的端口号不同时,也无法成功访问。
- 例: // 协议+主机名+端口号 任一 不相同!
www.baidu.com - > api.baidu.com
www.baidu.com - > tieba.baidu.com
www.baidu.com:80 - > www.baidu.com:8080
解决方案主要分为以下几种
一、CORS
解决方案
跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的Web应用被准许访问来自不同源服务器上的指定的资源。
后端接口中进行设置
通过利用CORS
,我们在前端只需要利用正常的ajax
请求方式即可,无需再设置回调函数。
@RestController
@RequestMapping("/api/customer")
public class HelloController {
@PostMapping("/getAllCustomerInfo")
public List<Customer> getAllCustomerInfo(HttpServletResponse response) {
// 设置响应头
response.setHeader("Access-Control-Allow-Origin", "*");
// 不再需要将结果放在回调函数中
return new ArrayList<>(Arrays.asList(
new Customer(1, "张三", "123456"),
new Customer(2, "李四", "654321"),
new Customer(3, "王五", "123123")
));
}
}
然后前端代码直接使用ajax
请求即可
// 首先需要引入 axios
<script src="https://cdn.staticfile.org/axios/0.1.0/axios.js"></script>
axios.post('http://localhost:8080/api/customer/getAllCustomerInfo')
.then(res => {
console.table(res, ['id', 'username', 'password'])
})
二、Nginx反向代理方式
通过使用Nginx
的反向代理,我们在后端接口中就可以去掉响应头的代码设置
@RestController
@RequestMapping("/api/customer")
public class HelloController {
@PostMapping("/getAllCustomerInfo")
public List<Customer> getAllCustomerInfo() {
return new ArrayList<>(Arrays.asList(
new Customer(1, "张三", "123456"),
new Customer(2, "李四", "654321"),
new Customer(3, "王五", "123123")
));
}
}
然后是在nginx.conf
中进行修改
server {
# 监听80端口, 前端不再直接访问8080端口, 改为访问80端口即可
listen 80;
server_name localhost;
location / {
root html;
# 添加头
add_header Access-Control-Allow-Origin *;
# 代理转发到8080后端端口
proxy_pass http://localhost:8080;
index index.html index.htm;
}
}
然后再将前端中访问的接口修改为80
// 首先需要引入 axios
<script src="https://cdn.staticfile.org/axios/0.1.0/axios.js"></script>
// 80为 http 默认端口,可省略
axios.post('http://localhost/api/customer/getAllCustomerInfo')
.then(res => {
console.table(res, ['id', 'username', 'password'])
})
解决
三、后端添加注解的方式
这种方式就比较简单粗暴,如果使用的是SpringBoot框架,直接在后端的Controller层中需要跨域的类或者方法上增加@CrossOrigin注解即可
参考文章:https://www.cnblogs.com/butterfly-fish/articles/15363543.html