前提

本来想写一个请求B站API用户粉丝数的函数、结果遇到了跨域的问题

然而通过设置了dataType: "jsonp"又遇到了这个问题

同源策略,它是由Netscape提出的一个著名的安全策略。现在所有支持JavaScript 的浏览器都会使用这个策略。

所谓同源是指,域名,协议,端口相同。当一个浏览器的两个tab页中分别打开来 百度和谷歌的页面。当浏览器的百度tab页执行一个脚本的时候会检查这个脚本是属于哪个页面的,即检查是否同源,只有和百度同源的脚本才会被执行。

如果非同源,那么在请求数据时,浏览器会在控制台中报一个异常,提示拒绝访问。通常这个异常以上面的形式存在着。

折腾了一天的跨域问题、终于得到了答案。。。

跨域

什么是跨域

跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript实施的安全限制。

同源策略限制了一下行为:

  • Cookie、LocalStorage 和 IndexDB 无法读取
  • DOM 和 JS 对象无法获取
  • Ajax请求发送不出去

当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域

当前页面url被请求页面url是否跨域原因
http://www.test.com/http://www.test.com/index.html同源(协议、域名、端口号相同)
http://www.test.com/https://www.test.com/index.html跨域协议不同(http/https)
http://www.test.com/http://www.baidu.com/跨域主域名不同(test/baidu)
http://www.test.com/http://blog.test.com/跨域子域名不同(www/blog)
http://www.test.com:8080/http://www.test.com:7001/跨域端口号不同(8080/7001)

Ajax接口数据类型

json格式

1
2
3
4
5
{
"message":"获取成功",
"state":"1",
"result":{"name":"zykj","id":1,"description":"zykjofficial"}
}

jsonp格式

1
2
3
4
5
callback({
"message":"获取成功",
"state":"1",
"result":{"name":"zykj","id":1,"description":"zykjofficial"}
})

我们可以看到,在url中callback传到后台的参数是什么callback就是什么,jsonp比json外面有多了一层,callback()。这样就知道怎么处理它了。于是修改后台代码。

jsonp(JSON with Padding) 是 json 的一种”使用模式”,可以让网页从别的域名(网站)那获取资料,即跨域读取数据。注意:jsonp只支持get请求

前端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
setTimeout(() => {
$.ajax({
url: "https://api.bilibili.com/x/space/acc/info?mid=241230332",
type: "get",
dataType: "jsonp",
jsonpCallback:"jsonp",
jsonp:"json",
success: function (data) {
console.log(data);
},
error: function () {
console.log("请求错误");
}
})
}, 1000)

后端代码

1
2
3
4
5
6
@RequestMapping("/userinfo/{uid}")
public String getUserInfo(@PathVariable String uid){
RestTemplate template = new RestTemplate();
Object forObject = template.getForObject("https://api.bilibili.com/x/space/acc/info?mid="+uid, Object.class);
return "jsonp("+JSON.toJSONString(forObject)+")";
}

自己的理解就是后台请求B站API返回的数据转换成JSON数据、套入jsonp()并且返回给请求者、相当于自己把数据封装了一下。

这样就可以请求到了。

参考文章