WordPress URL生成的”薛定谔协议”
在wordpress调试url生成规则时,发现一个有意思现象。如下
if ( is_array( $args[0] ) ) {
if ( count( $args ) < 2 || false === $args[1] ) {
$uri = $_SERVER['REQUEST_URI'];
} else {
$uri = $args[1];
}
} else {
if ( count( $args ) < 3 || false === $args[2] ) {
$uri = $_SERVER['REQUEST_URI'];
} else {
$uri = $args[2];
}
打印$args结果如下:
Array
(
[0] => filter_size
[1] =>
[2] => //localhost:3000/shop/?filter_size=35-5%2C36&query_type_size=or&filter_gender=woman&query_type_gender=or
)
然后继续执行以下代码:
if ( 0 === stripos( $uri, 'http://' ) ) {
$protocol = 'http://';
$uri = substr( $uri, 7 );
} elseif ( 0 === stripos( $uri, 'https://' ) ) {
$protocol = 'https://';
$uri = substr( $uri, 8 );
} else {
$protocol = '';
}
代码中 $uri 是以 //localhost:3000 开头(无协议)
所以理论上,这段代码
if ( 0 === stripos( $uri, ‘http://’ ) )
应该条件不满足,但是,我调试了,发现被执行了,如下:
if ( 0 === stripos( $uri, 'http://' ) ) {
print_r('$urii-1:');
print_r($uri);
echo '<br>';
$urii-1://localhost:3000/shop/?filter_size=35-5%2C36&query_type_size=or&filter_gender=woman&query_type_gender=or
执行后,继续打印查看$uri变量,变成如下:
localhost/shop/?filter_size=35-5%2C36&query_type_size=or&filter_gender=woman&query_type_gender=or
是不是很奇怪?我确实是用BrowserSync 运行 3000 端口,但是它能“智能识别”,把url还原成原来的地址。然后“正确判断并执行”:
if ( 0 === stripos( $uri, ‘http://’ ) ) {
$protocol = ‘http://’;
$uri = substr( $uri, 7 );
}
而且,在后续重新构建 URL时,又能还原成被BrowserSync代理的地址,测试如下:
print_r('$protocol1:');
print_r($protocol);
echo '<br>';
print_r('$base1:');
print_r($base);
echo '<br>';
$ret = $protocol . $base . $ret . $frag;
print_r('$ret3:');
print_r($ret);
打印结果如下:
$protocol1:http://
$base1:localhost/shop/?
$ret3://localhost:3000/shop/?query_type_size=or&filter_gender=woman&query_type_gender=or
最终URL中 3000 端口的”幽灵再现”现象,是不是很神奇,它能“智能”识别:
$protocol . $base
拼接后,神奇地变回了
//localhost:3000/shop/?
而不是预期的
http://localhost/shop/?
为什么呢?
原因分析:
继续调试,对
$protocol . $base . $ret . $frag
其值如下:
$protocol1:http://
$base1:localhost/shop/?
$ret3://localhost:3000/shop/?query_type_size=or&filter_gender=woman&query_type_gender=or
对四个变量不同组合测试。
$a1 = $ret .$protocol;
print_r('$a1:');
print_r($a1);
echo '<br>';
$a2 = $ret .$base;
print_r('$a2:');
print_r($a2);
echo '<br>';
$a3 = $base.$protocol;
print_r('$a3:');
print_r($a3);
echo '<br>';
$a4 = $protocol.$base;
print_r('$a4:');
print_r($a4);
echo '<br>';
$a5 = substr($protocol.$base,2);
print_r('$a5:');
print_r($a5);
echo '<br>';
print_r('$a6:');
print_r('http://localhost/shop/?');
echo '<br>';
$ret = $protocol . $base . $ret . $frag;
print_r('$ret3:');
print_r($ret);
打印结果如下:
$a1:query_type_size=or&filter_gender=woman&query_type_gender=orhttp://
$a2:query_type_size=or&filter_gender=woman&query_type_gender=orlocalhost/shop/?
$a3:localhost/shop/?http://
$a4://localhost:3000/shop/?
$a5:tp://localhost/shop/?
$a6://localhost:3000/shop/?
$ret3://localhost:3000/shop/?query_type_size=or&filter_gender=woman&query_type_gender=or
分析现象,很有意思。$a1、$a2、$a3值打印出来跟预期一样,但是$a4,打印出来变成了
//localhost:3000/shop/?
而不是预期的
http://localhost/shop/?
然后我把$a5故意截掉部分http,又符合预期打印了。
最后$a6干脆直接赋值,发现打印出来有变成
$a6://localhost:3000/shop/?
经此,测试完毕,结果显而易见,是BrowserSync在作崇。
本人BrowserSync 运行 3000 端口。浏览器访问 http://localhost:3000,请求被转发到后端WEB服务器 Apache的80端口,所以后端处理的url是被还原的url。
然后后端处理url之后,返回前端时,其 HTML 内容会被BrowserSync 拦截,并修改其中的 URL。将绝对 URL(http://localhost/shop/)改写为协议相对 + 端口(//localhost:3000/shop/)。所以我在浏览器界面看到的这些变量打印输出,实际上是被BrowserSync拦截并修改后的显示结果。
而实际上,在php层面代码url代码一直都是原来的、未被BrowserSync所代理的地址。从$a6直接赋值打印就可以证明这一点。
以上,其实说白了,彻底了解原理之后,回顾上述过程,是一件非常简单的问题,但就是很简单,由于你不了解,就得不断代码调试,就会被折腾了很久。但这个解决问题的过程还是很值的,它既拓展了知识面,又锻炼了问题解决能力。所以,也要善于折腾!