BrowserSync-wordpress调试拼接url时发现一个有意思现象

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直接赋值打印就可以证明这一点。

以上,其实说白了,彻底了解原理之后,回顾上述过程,是一件非常简单的问题,但就是很简单,由于你不了解,就得不断代码调试,就会被折腾了很久。但这个解决问题的过程还是很值的,它既拓展了知识面,又锻炼了问题解决能力。所以,也要善于折腾!