前端模拟服务器实现跨域

DEMO

https://github.com/abigaleypc/cross-domain-server

项目安装

  • git clone https://github.com/abigaleypc/cross-domain-server
  • cd JSONP
  • npm install

不同域的定义

协议+域名+端口号都相同才是同域

XMLHttpRequest跨域访问

通过以上例子我们已经可以通过 XMLHttpRequest 对象实现一个HTTP请求,但以上方法只能向同域下进行请求

XHR/port8080

1
request.open('GET', 'http://127.0.0.1:8080/test.txt');

XHR/port58023

1
request.open('GET', 'http://127.0.0.1:58023/test.txt');

如果我在 port8080 中将 58023 改为 8080,可以看到浏览器报了以下错误

跨域错误

这就出现了跨域的问题(端口号不同)。

JSONP解决跨域问题

简单理解下JSONP的原理:AJAX不能实现跨域的请求,但却能将不能请求的文件通过 <script>获取到,如 <script src="xxx.js"></script>详细文档

tip: port8080主要用来访问不同域的子项目,port58023主要模拟服务器,启动另一个端口给port8080访问

cd JSONP

在文件夹 JSONP/port8080/index.html 中,我们引入的是另一个端口下的文件,文件同样获取到了,这时候打开浏览器控制台可以看到返回结果被打印出来了。

1
2
3
4
5
6
<script>
function callback(data) {
console.log(data)
}
</script>
<script src="http://127.0.0.1:58023/test.js"></script>

在文件夹 JSONP/port58023 中,我们可以看下 test.js文件

1
2
3
4
5
callback(
{
"port": "我不是8080端口"
}
)

控制台已经打印出文本,只是因为 callback() 函数被调用并被打印出来了。

以上就是JSONP的实现原理。一般情况下,我们希望这个script标签能够动态的调用,而不是像上面因为固定在html里面所以没等页面显示就执行了,很不灵活。我们可以通过javascript动态的创建script标签,这样我们就可以灵活调用远程服务了。

我们可以将 JSONP/post8080/index.html 脚本改成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script type="text/javascript">
function callback(data) {
alert(data.message);
}
// 添加<script>标签的方法
function addScriptTag(url){
var script = document.createElement('script');
script.setAttribute("type","text/javascript");
script.src = url;
document.body.appendChild(script);
}
window.onload = function(){
addScriptTag("http://localhost:20002/test.js");
}
</script>

实现以上过程的前提是后端提供callback字段,如https://api.douban.com/v2/user/abigaleypc?callback=__callback5,我们可以在参数加上callback是因为后端的支持,就像以上 JSONP/port58023/test.js

1
2
3
4
5
callback(
{
"port": "我不是8080端口"
}
)