坑点and埋坑点 - header重定向后取不到referer

  • 作者:KK

  • 发表日期:2016.12.23


要点速读

如果从a.php执行header('Location: b.php');跳转到b.php后,在b.php里echo $_SERVER['HTTP_REFERER'];通常情况下会提示undefined

注意只是通常情况下

也结合此文:《HTTP请求头与SERVER数组》可以知道,我们访问$_SERVER['HTTP_REFERER']时始终都应该加isset判断


准备测试代码

先给出以下三个文件的代码

a.php:

header('Location: b.php');

到b.php:

echo $_SERVER['HTTP_REFERER'];

index.php:

<script src="http://www.kkh86.com/js/jquery-1.11.1.min.js"></script>
<script>
location.href = 'a.php';

/*
$.ajax({
	url : 'a.php',
	success : function(result){
		console.log(result);
	}
});
*/
</script>
<a href="index.php">和JS跳一样的效果,反正都是通过document来跳</a>

开始测试

  • 测试方式1:直接请求带有header跳转的地址(a.php)

    访问a.php就会马上执行header,结果去了b.php后提示undefined

    结论:访问的地址如果有header('Location:$url')的时候,跳转的目标地址不会收到referer这个请求头


  • 测试方式2:通过JS代码跳转到a.php

    访问index.php就会执行location.href跳转,然后也是到了b.php但却看到了$_SERVER['HTTP_REFERER']的值

    结论:用前端跳转就可以有referer,可以初步猜测referer是浏览器包装后才发给后端的


  • 测试方式3:用ajax请求a.php

    再把index.php的location.href注释掉,换成下面的ajax代码请求a.php,也会看到返回值

    并且会看到有两个请求地址,第一个地址是“a.php”的(并且没有响应内容,看响应头),第二个就是“b.php”

    之所以一次ajax产生2次请求,是因为ajax在收到Location这个响应头后就自动再发了个请求给重定向的地址,因为在ajax的理解里应该是“是服务端让我掉头找另一个地址要数据的


  • 测试方式4:点击a标签跳转到a.php

    结果也是输出了referer


最终的简单结论就是:如果直接访问的地址就响应了Location这个报头字段,则浏览器马上请求的新地址无法获取到referer

相关参考:RFC 1945号文档10.13章节提到referer这个请求头字段是允许客户端发给服务端的

真相:其实referer通常是要document发出请求才有的,而直接请求一个地址时如果还没输出HTML就先发了报头,此时document对象还未产生,所以这个跳转无法构造referer发给服务端。本文章的测试方式2、3、4中能让服务端得到referer字段正是因为它们是在浏览器已经构造了document对象之后通过前端代码发出请求的