先 logout 知乎网页。 然后浏览 http://www.zhihu.com/question/20381025。
就会看见 5 秒后将会跳转信息:
五秒过后, 跳去 www.zhihu.com/question/19694728?rf=20381025:
五秒过后, 又再跳去 www.zhihu.com/question/22447061?rf=19694728:
还没跳完,五秒过后, 又再跳去 www.zhihu.com/question/20135771?rf=22447061:
五秒过后, 跳去 www.zhihu.com/question/24531839?rf=20135771:
终于跳完 liao~ 是不是很好玩叻。当然你会觉得知乎 desgin 到酱真的是。。。
为什么我要强调 logout ? 因为 login 对知乎的重定向很大影响哦。如果没有 login, 以上所有的重定向都是交给了 js 来处理。 如果有 login,第一个重定向交给 302 处理 (所以你看不见第一页, 而是直接跳到第二页。
来证明一下,login 知乎后, 然后打开 http://www.zhihu.com/question/20381025
留意 URL bar, 是不是很奇怪叻, 直接 skip 掉 20381025 跳第二页。哦, 我还没讲上述 URL 的结构。
http://www.zhihu.com/question/问题_ID?rf=上一个重定向问题_ID
就这样, rf 猜到就是 referer 的简称。
不止这个特别,还会出现从什么问题跳转过来的信息。这就是 login 的特别之处。不但 skip 掉第一个 302, 而且会留意从哪里来。
那么如果想看回重定向之前的那页怎么办 ? 只要来得及按 "从问题 xxxxx 跳转而来" 就能看回之前那页, 并且不再重定向。这种设计,用户怎么可能懂呢 ?
login 的影响 inconsistent 的 behavior 还没完。"从问题 xxxxx 跳转而来" 本身就是 URL 加上 nr=1, 即是 no-redirect 的简称。 如果你没有 login, 你看不见 "从问题 xxxxx 跳转而来" 这行字也就算了,可是如果你手动把 URL 加上 nr=1, 比如 www.zhihu.com/question/20381025?nr=1:
还是会再跳的哦, 也就是说 login 不仅仅影响 302+js 重定向以及 block 掉 rf 信息, 而且也不允许 nr 的功能。
当然我是能想到 302+js 的初衷。302 省一次重定向, 然后又不想用户完全不懂第一页的题目, 所以只 302 静悄悄重定向一次, 接下来就用 "从问题 xxxxx 跳转而来" + js 方法重定向下一页。至于为什么要 login only 就感觉像 bug 多一点。
你可能看不懂我讲什么鬼, 简单一句, 如果是 http://www.zhihu.com/question/问题_ID?rf=上一个重定向问题_ID 链接就加上 &nr=1, 改成
http://www.zhihu.com/question/问题_ID?rf=上一个重定向问题_ID&nr=1 ,如果是 http://www.zhihu.com/question/问题_ID 链接就改成 http://www.zhihu.com/question/问题_ID?nr=1, 并且在 login 的情况下,链接是不会自动重定向的哦。
接下来让我们 DIY 两种重定向规则。
先准备 google chrome 浏览器。目标是自制 chrome extension。
准备两个 file, hello_inject.js 以及 manifest.json 放在同一个 directory/folder:
hello_inject.js 源码:
chrome.webRequest.onBeforeRequest.addListener( function(details) { if (details.url && /^https?:\/\/www.zhihu.com\/question\/\d+/i.test(details.url)) { var url = details.url; var paramName = "nr"; var paramValue = "1"; var splitAtAnchor = url.split('#'); url = splitAtAnchor[0]; var anchor = typeof splitAtAnchor[1] === 'undefined' ? '' : '#' + splitAtAnchor[1]; if (url.indexOf(paramName + "=") >= 0) { var prefix = url.substring(0, url.indexOf(paramName)); var suffix = url.substring(url.indexOf(paramName)); suffix = suffix.substring(suffix.indexOf("=") + 1); suffix = (suffix.indexOf("&") >= 0) ? suffix.substring(suffix.indexOf("&")) : ""; url = prefix + paramName + "=" + paramValue + suffix; } else { if (url.indexOf("?") < 0) url += "?" + paramName + "=" + paramValue; else url += "&" + paramName + "=" + paramValue; } console.log("injected url: " + url + anchor); return {redirectUrl: url + anchor}; } }, {urls: ["<all_urls>"]}, ["blocking"]);
manifest.json 源码:
{ "name": "URL Injector", "version": "1.0", "description": "Injet url.", "background": { "scripts": ["hello_inject.js"] }, "manifest_version": 2, "permissions": [ "contextMenus", "storage", "webRequest", "webRequestBlocking", "tabs", "http://*/*", "https://*/*" ] }
然后去 chrome://extensions, 右手边打勾 Developer mode, 然后按 Load unpacked extension...:
选你刚才那个 directory/folder, 按 Open:
login 情况下,然后浏览 http://www.zhihu.com/question/20381025。
yeah, inject nr=1 成功 :)。现在每一跳问题都会自动加上 nr=1 不再跳转。当然, 必须 login 哟。
如果你不要 print log 就前面加上 // 来 comment out console.log,
//console.log("redirect url: " + url + anchor);
如果更改储存 hello_inject.js 源码文件后, 必须在 chrome://extensions/ 页面, Ctrl+r 更新 take effect。
另一种玩法是选择直接强迫它 302 redirect。原理就是依赖 login + 把 rf 丢掉。因前面研究过,我们已经懂第一页是 302, 特征就是第一页没有 rf 然后接下来有 rf。
hello_inject.js 源码:
chrome.webRequest.onBeforeRequest.addListener( function(details) { if (details.url && /^https?:\/\/www.zhihu.com\/question\//i.test(details.url)) { var url = details.url; var base = url.substring(0, url.indexOf("?")); var queryString = url.substring(url.indexOf("?") + 1); var params = queryString.split("&"); var valid_param = 0; var invalid_param = 0; for (var i = 0; i < params.length; i++) { var p = params[i].split("="); if ((params[i] !== p[0]) && ( p[0] == "rf" )) { invalid_param+=1; } else { if (valid_param !== 0) { base+=params[i]; valid_param+=1; } else { base = base + "?" + params[i]; } } } if (invalid_param !== 0) { console.log("redirect base: " + base); return {redirectUrl: base}; } } }, {urls: ["<all_urls>"]}, ["blocking"]);
Ctrl+r 更新 extension, login 情况下浏览 http://www.zhihu.com/question/20381025 就会直接 skip 到最后一页 24531839:
如果 Inspect element 检测, 就能看到 302 -> 307(Internal Redirect) -> 302 -> 307 -> 302 -> 307 -> 302 -> 307 skip 到最后一页 200 OK。省下中间的 download。