起因
原来就听别人说过“跨域”这个概念,当时并没有太在意。然而,在近些天的Spring Cloud学习过程中,在前后端分离的模式下进行数据交互时,跨域请求成为了我的最大麻烦。目前通过各种方法克服了一些跨域的问题,但还不能说十分熟悉,就现已目前的认知与经验,小记一下。
这个时是我练习项目的gitee地址:https://gitee.com/z_h_r/bill-management-microservice-rebuild
什么是跨域
要说跨域,先要提另一个名词——“同源”
关于同源
- 在我们日常使用的各种Browser中,存在一个被称为“同源策略”的机制。
- 同源策略是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。
- 可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。
- 同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。
- 所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机名(IP地址)和端口号(port)。
看完这些,你大概也猜到跨域是什么意思了。
关于跨域
当一个请求URL的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域。
跨域的限制
- 无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB。
- 无法接触非同源网页的 DOM。
- 无法向非同源地址发送 AJAX 请求(最常见)。
关于CORS
CORS 是跨域资源分享(Cross-Origin Resource Sharing)的缩写。它是 W3C 标准,属于跨源 AJAX 请求的根本解决方法。
微服务间解决跨域问题的方法
image.png
在Spring Cloud各个微服务之间,跨域问题十分普遍,鉴于我们目前能力有限,下面我就就我在实践中遇上的前后端分离数据交互时的跨域问题稍微谈谈。
1. Jsonp
看了好多关于“解决JQuery Ajax 跨域调用问题”的文章,都谈到了这个Jsonp,但可操作性很差,各路讲解也是关键地方模棱两可,关键代码没有任何注释讲解,在尝试了各种关于Jsonp的方法后也没能解决问题,只能返回JSON,但填不进DOM。Java的小伙伴慎重考虑Jsonp。下面附些链接,可以感受下:
- 朦胧概念篇
菜鸟Jsonp教程:https://www.runoob.com/json/json-jsonp.html - 实践博客篇
2. 服务端配置
我最终是通过在Controller中进行配置解决跨域问题的。这是一个Controller中的一个方法,有两种方式是数据可以跨域交互:
@RequestMapping("/list-page")
@ResponseBody
//方法一: 添加注解
@CrossOrigin
public Object[] listPage(
@RequestParam(defaultValue = "1") int pageNum,
@RequestParam(defaultValue = "10") int pageSize,
Bill bill,
HttpServletResponse response) {
List<BillType> types = typeService.list();
PageInfo<Bill> page = billService.listPage(bill, pageNum, pageSize);
//方法二: 通过response对象进行响应头配置
// response.setHeader("Access-Control-Allow-Origin", "*");
return new Object[]{types,page,bill};
}
前端Ajax
function f() {
$.ajax({
url: "http://localhost:8086/api/bill/list-page",
dataType:"json",
data: {
pageNum:$("#pageNum").val(),
pageSize:$("#pageSize").val(),
// date1:$("#date1").val()==''?'2000-10-01':$("#date1"),
// date2:$("#date2").val()==''?'2022-10-01':$("#date2")
},
async:true,
type: "get",
success: function(data){
callback(data);
}
});
}
function callback(data){
let types = data[0];
let ppage = data[1];
let bill = data[2];
sessionStorage.setItem("types", types);
sessionStorage.setItem("page", ppage);
sessionStorage.setItem("bill", bill);
$("#pageNum").val(ppage.pageNum);
$("#pageSize").val(ppage.pageSize);
for (let i = 0; i < types.length; i++) {
console.log(i);
let t = types[i];
$("#typeId").append($("<option value=\"" + t.id + "\" >" + t.name + "</option>"));
if (bill.typeId === t.id) {
$(this).prop("selected");
}
}
let date1 = bill.date1;
let date2 = bill.date2;
$("#date1").val(date1);
$("#date2").val(date2);
let ttbb = $("#ttbb");
for (let i = 0; i < ppage.list.length; i++) {
let b = ppage.list[i];
ttbb.append("<tr>");
ttbb.append("<th>" + b.id + "</th>");
ttbb.append("<td>" + b.title + "</td>");
ttbb.append("<td>" + b.billTime + "</td>");
ttbb.append("<td>" + b.price + "</td>");
ttbb.append("<td>" + b.typeName + "</td>");
ttbb.append("<td>" + b.explain + "</td>");
ttbb.append("<td><a href='update.html' class='btn btn-primary mx-2'>修改</a>" +
"<a href=\"http://localhost:8086/api/bill/delete/"+b.id+"\" class='btn btn-primary mx-2'>删除</a></td>");
ttbb.append("</tr>");
}
let ps = ppage.navigatepageNums;
for (let i = 0; i < ps.length; i++) {
$("#lili").append("<button class='btn btn-default' name='pa'>" + ps[i] + "</button>");
}
}
onload=function(){
f();
}
先说到这,等技术更深一步后再补充。