前面写的程序没有涉及跨越问题,一直也没有关注,昨天需要解决一下跨越问题,想一想以后还要做单点登录,稍微复杂一点的应用也必然会涉及这个知识点,有必要总结一下。
访问一个网页是由协议、域名、端口组成的,所谓同源就是域名,协议,端口都相同,否则就是非同源,也就是涉及跨域访问。
跨域(跨域资源共享,Cross-Origin Resources Sharing,CORS)访问是针对浏览器访问而产生的,就是处于A域中的网页脚本去访问B域中的网页脚本,直白说就是从当前域名的网站下不能请求非同源的其他地址。
一般情况下,不允许跨越访问,它是由浏览器的同源策略所导致的,也是为了安全,想一想,如果没有这个限制,访问一个网站,网站脚本就可以获取所有用户访问过的信息,包括一些涉密的信息,这是很危险的。
这方面的知识点网络上讲解的很多。
重点掌握一些细节知识点。
1、通过<Script src=""></Script>这样的方式引用不存在跨域访问。
在网页程序里,一般都有外在的引用,比如引用一些常用的框架等,这是因为通过<Script src=""></Script>这样的方式引用不存在跨域访问。
例如:
⑴ 启动Apache服务器,监听8008端口,GetDataFromPHP.php的脚本:
<?php
echo "var SDF='这是变量SDF'";
?>
⑵ 启动Tomcat服务器,监听9019端口,网页TomcatIndex.html里的脚本:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>跨越访问</title>
<script src="http://127.0.0.1:8008/PHP2021/CORS/GetDataFromPHP.php" id="PK"></script>
</head>
<body>
<h1>Tomcat服务器:http://127.0.0.1:9019</h1>
访问当前网页使用的协议:<input type="text" id="protocol"/>
<br>
访问当前网页所在的域名:<input type="text" id="domain"/>
<br>
访问当前网页使用的端口:<input type="text" id="port"/>
<script>
alert(SDF);
document.getElementById("domain").value=document.domain;
document.getElementById("port").value=location.port;
document.getElementById("protocol").value=location.protocol;
</script>
</body>
</html>
⑶ 浏览http://127.0.0.1:9019/CORS/TomCatIndex.html,则会弹出显示框:
这一方面说明了通过<Script src=""></Script>这样的方式引用不存在跨域访问,加载进来的内容是直接放到内存里的可执行区域,这也提示我们可以通过这样的方式来实现跨越访问。
变化举例:
⑴ GetDataFromPHP.php的脚本:
<?php
echo "func('这是变量SDF')";
?>
⑵ TomcatIndex.html的脚本:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>跨越访问</title>
</head>
<body>
<h1>Tomcat服务器:http://127.0.0.1:9019</h1>
访问当前网页使用的协议:<input type="text" id="protocol"/>
<br>
访问当前网页所在的域名:<input type="text" id="domain"/>
<br>
访问当前网页使用的端口:<input type="text" id="port"/>
<script>
function func(data){
alert(data);
}
document.getElementById("domain").value=document.domain;
document.getElementById("port").value=location.port;
document.getElementById("protocol").value=location.protocol;
</script>
</body>
<script src="http://127.0.0.1:8008/PHP2021/CORS/GetDataFromPHP.php" id="PK"></script>
</html>
⑶ 浏览http://127.0.0.1:9019/CORS/TomCatIndex.html,同样会弹出上面的显示框。
其实,通过链接link、iframe、img等方式都不存在跨域访问的问题,通过iframe方式稍微麻烦一点,也不常用,通过Script方式我们可以写自己的一些简易框架进行加载来实现一些常用的功能或画面,这是重点。
2、通过动态调整<Script src=""></Script>来实现跨域访问。
⑴ GetDataFromPHP.php的脚本:
<?php
echo "var SDF='123'";
?>
⑵ TomcatIndex.html的脚本:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>跨越访问</title>
<script src="" id="PK"></script>
</head>
<body>
<h1>Tomcat服务器:http://127.0.0.1:9019</h1>
访问当前网页使用的协议:<input type="text" id="protocol"/>
<br>
访问当前网页所在的域名:<input type="text" id="domain"/>
<br>
访问当前网页使用的端口:<input type="text" id="port"/>
<br>
<a onclick="test2()">点击通过JavaScript脚本得到PHP的返回数据:http://127.0.0.1:8008/PHP2021/CORS/GetDataFromPHP.php</a>
<script>
document.getElementById("domain").value=document.domain;
document.getElementById("port").value=location.port;
document.getElementById("protocol").value=location.protocol;
function test2(){
ScriptObj = document.getElementById("PK");
var head = document.getElementsByTagName("head").item(0);
if (ScriptObj) {
head.removeChild(ScriptObj);
}
ScriptObj = document.createElement("script");
ScriptObj.setAttribute("src", "http://127.0.0.1:8008/PHP2021/CORS/GetDataFromPHP.php");
ScriptObj.setAttribute("id","PK");
ScriptObj.setAttribute("type","text/javascript");
ScriptObj.setAttribute("language","javascript");
head.appendChild(ScriptObj);
setTimeout( function(){ console.log(SDF);},1000)
}
</script>
</body>
</html>
⑶ 浏览http://127.0.0.1:9019/CORS/TomCatIndex.html,则显示下面的结果:
上面的解决办法也解释了一种传输协议,就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以通过编写的函数来处理返回数据,这种传输协议也称为JsonP。
当然我们不需要这么麻烦来这样做,JQuery已经为我们做好了。
3、通过JQuery的Ajax来实现跨域访问。
⑴ GetDataFromPHP.php的脚本:
<?php
$returnArr=[];//准备返回的数组
$returnArr=array("name"=>"PHP","age"=>"7");
$callback=$_GET['callback'];
echo $callback."(".json_encode($returnArr).")";
?>
⑵ TomcatIndex.html的脚本:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>跨越访问</title>
<script src="jquery-3.4.1.min.js"></script>
</head>
<body>
<h1>Tomcat服务器:http://127.0.0.1:9019</h1>
访问当前网页使用的协议:<input type="text" id="protocol"/>
<br>
访问当前网页所在的域名:<input type="text" id="domain"/>
<br>
访问当前网页使用的端口:<input type="text" id="port"/>
<br>
<a onclick="GetDataFromHPHP()">点击通过AJAX得到PHP的返回数据:http://127.0.0.1:8008/PHP2021/CORS/GetDataFromPHP.php</a>
<br>
结果:<input type="text" id="data1"/>
<script>
document.getElementById("domain").value=document.domain;
document.getElementById("port").value=location.port;
document.getElementById("protocol").value=location.protocol;
function GetDataFromHPHP(){
$.ajax({
url: 'http://127.0.0.1:8008/PHP2021/CORS/GetDataFromPHP.php',
method:'get',
dataType:'jsonp',
success: function(data) {
console.log(data);
document.getElementById("data1").value = data.name+","+data.age;
}
});
}
</script>
</body>
</html>
⑶ 浏览http://127.0.0.1:9019/CORS/TomCatIndex.html,则显示下面的结果:
4、通过nginx的反向代理来实现跨域访问。
⑴ GetDataFromPHP.php的脚本:
<?php
$returnArr=[];//准备返回的数组
$returnArr=array("name"=>"PHP","age"=>"7");
header('Content-type:text/json');
echo json_encode($returnArr,JSON_UNESCAPED_UNICODE);
?>
⑵ TomcatIndex.html的脚本:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>跨越访问</title>
<script src="jquery-3.4.1.min.js"></script>
</head>
<body>
<h1>Tomcat服务器:http://127.0.0.1:9019</h1>
访问当前网页使用的协议:<input type="text" id="protocol"/>
<br>
访问当前网页所在的域名:<input type="text" id="domain"/>
<br>
访问当前网页使用的端口:<input type="text" id="port"/>
<br>
<a onclick="GetDataFromHPHP()">通过nginx实现跨越访问:http://127.0.0.1:9001/PHP2021/CORS/GetDataFromPHP.php</a>
<br>
结果:<input type="text" id="data1"/>
<br>
<a href="http://127.0.0.1:8008/PHP2021/CORS/GetDataFromPHP.php">点击显示来自http://127.0.0.1:8008/PHP2021/CORS/GetDataFromPHP.php的数据</a>
<script>
function GetDataFromHPHP(){
$.ajax({
url: 'http://127.0.0.1:9001/PHP2021/CORS/GetDataFromPHP.php',
method:'post',
datatype:'json',
success: function(data) {
console.log(data);
document.getElementById("data1").value = data;
}
});
}
</script>
</body>
</html>
⑶ nginx的配置:
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 9001;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root G:/nginx/html;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:8008
#
location ~ \.php$ {
# 指定允许跨域的方法,*代表所有方法,也可指定具体的方法。
add_header Access-Control-Allow-Methods $http_access_control_request_method;
# 预检命令的缓存,如果不缓存每次会发送两次请求
add_header Access-Control-Max-Age 3600;
# 有cookie访问请求的要加上这个设置
add_header Access-Control-Allow-Credentials true;
# 允许这个域跨域调用
add_header Access-Control-Allow-Origin $http_origin;
# 动态获取请求头的字段
add_header Access-Control-Allow-Headers $http_access_control_request_headers;
proxy_pass http://127.0.0.1:8008;
}
location ~ \.do$ {
proxy_pass http://127.0.0.1:9019;
}
}
}
⑷ 浏览http://127.0.0.1:9019/CORS/TomCatIndex.html,点击通过nginx实现跨越访问则显示下面的结果: