黑帽SEO技術不論多么神奇,不管用戶看到的頁面多么的敏感,但是搜索引擎爬蟲看到的永遠都是正規的信息,而用戶看到的是非常規信息。很明顯,這是因為網站頁面做了處理,能夠分辨出普通用戶和搜索引擎,不同的對象調用不同的頁面,這個就是網站頁面跳轉。
什么是網站頁面跳轉以及為什么要進行頁面跳轉就不多去細說了,那么怎么進行頁面跳轉呢。關于網頁跳轉技術很多,文章也很多,方法代碼都很多,但是這些方法差別在那里,那些方法速度更快,那些方法更靈活,那些方法用戶能感覺到,為什么能感覺到。夜島SEO看了一些文章,結合多年的黑帽SEO優化工作經驗,通過繪制序列圖等辦法簡單總結一下,換個角度理解一下,希望對大家有所幫助!
本文夜島重點在于比較http跳轉,html跳轉,js跳轉的工作流程,以及重點分析他們在時間開銷上的情況,同時我們重點在于繪制一些圖形,然后希望讀者能夠從圖中體會到區別,需要讀者體會的地方都用特別區域標識出來了。請大家注意。
網站都是由各種各樣頁面組成,正常情況下A頁面里面包含B頁面,C頁面的鏈接,用戶在瀏覽A頁面過程中,手工人為點擊B鏈接,然后用戶瀏覽器就顯示到B頁面。這個過程我們就可以叫頁面跳轉。
黑帽SEO中常用的站群排名技術99.9%是必須要做跳轉的,不然排名上去了給客戶看什么內容呢。我們考慮如下場景,一個網站由A,B,C頁面構成。正常他們有他們自己顯示內容。隨著時間推移,發現A頁面內容應該同C頁面內容相同,但是由于A頁面已經被大量用戶收藏在瀏覽器的收藏夾中,或者被搜索引擎收錄,若是現在取消A頁面的地址(就是取消頁面),則對用戶是個非常糟糕的事情,但是同時維護兩個頁面A及C又是個麻煩的事情,稍有疏忽就會造成內容不一致,給用戶造成困惑,同時搜索引擎也會不認可。
如何保證A地址不取消,同時又準確保證兩個頁面顯示內容相一致?
我們今天要解決的是在沒有用戶干預下的頁面跳轉,完成當用戶需要顯示頁面A時,我們給他顯示頁面C的內容。
另外為了說明問題方便,我們同時也假設頁面B內容也指向內容C,只是采用跳轉技術不一樣,這樣我們方便區別兩種行為的差別。
如上圖中,展示了用戶訪問服務器獲取頁面的一個基本過程。圖中主要分為兩個部分,左側區域是用戶端,右側區域是服務端,用戶端的用戶通過手機或者電腦或者智能設備訪問服務端頁面。
服務端由若干頁面構成,這里簡化了服務端行為,并且抽象成三個頁面A,B,C,正常情況下服務端應該有很多Action對象,Action對象同頁面相對應,提供各種服務,我們僅僅簡化Page:A,Page:B,Page:C;
用戶端就是手機,包括手機操作操作系統,網絡層(tcp/ip/udp等),http等協議層,以及瀏覽器,瀏覽器內部進行html的解析,css渲染,js執行引擎等等。
1.用戶啟動瀏覽器
2.在瀏覽器地址中輸入域名url地址
3.瀏覽器發起http請求
4.網絡層發起tcp請求到服務器,傳輸http數據包
5.服務器接收到請求后進行處理,然后返回相關頁面內容
6.Tcp接收返回數據給http協議解析系統
7.http將返回數據返回瀏覽器
8.瀏覽器解析html數據,處理htmlhead
9.根據head處理后續工作
10.解析body數據
11.處理裝載事件Onload(已經開始js的執行,在裝入數據過程中已經可以執行一些js事件,具體要根據頁面以及瀏覽器特性而定)
12.根據css進行顯示,執行js
13.用戶進行后續事情
以上僅僅是典型瀏覽器行為,具體瀏覽器行為同頁面內容、瀏覽器特性等都有關系,要具體分析。
根據上面的圖1,我們可以有如下分類方法:
一)以跳轉地點發生系統那一側分為:
頁面跳轉發生在服務端,服務端負責將實際內容獲取,然后發送給客戶端,這個情況下,一般用戶不會感覺到跳轉的實際行為,因此有些時候我們也不叫做跳轉。具體的服務端跳轉行為有很多,各個技術都有各自的特點。例如:Struts2基于注解服務端跳轉、<request.getRequestDispatcher(“xx.jsp”).forward(request,response)、<jsp:forwardpage=””/>等,php也有自己的放回,總之各自有各自的辦法,夜島就不一一舉例了,大家自己去搜索吧。
跳轉行為需要客戶單程序參與的一種行為(自然不是用戶參與的,那個不是本文討論的)。在這個過程中,一般用戶一定會知道的,瀏覽器地址欄會發生變化,這個分類比較多,我們專門進行一個分類。
二)用戶端跳轉中,我們根據跳轉行為發生在那個軟件層次,分為:http層跳轉、應用層跳轉;應用層跳轉繼續分為:htmlhead跳轉、js跳轉等。
http跳轉是指server根據工作情況通過http返回狀態碼,指示客戶端瀏覽器跳轉到相應頁面的過程,一般返回碼是302.,下面是http302狀態碼的定義:
Htmlhead頭指令跳轉
在html代碼的head中添加特殊標簽,如下
<metahttp-equiv=”refresh”content=”5;url=http://www.heimaoke.com/”/>
表示:5秒之后轉到黑帽客網站首頁。
這個跳轉需要瀏覽器具體解析html后才能進行,慎重更多時間才能進行,或者情況更復雜。
通過在html代碼中添加js代碼,通過js代碼實現跳轉
<scriptlanguage=”javascript”type=”text/javascript”>
window.location.href=”login.jsp?backurl=”+window.location.href;
</script>
這個跳轉應該比htmlhead跳轉更向后延遲。
頁面跳轉顯示的內容發生在服務端,服務端負責將實際內容獲取到,然后發送給客戶端。一般用戶不會感覺到跳轉的實際行為,因此有些時候我們也不叫做跳轉
具體工作的參考過程如下:
如上圖,用戶請求訪問PageA,頁面A內容指向頁面C,相關過程如下:
1.用戶通過瀏覽器訪問PageA
2.瀏覽器通過http處理模塊請求GetPageA
3.http處理模塊同服務器建立tcp連接,并發出請求獲取PageA指令
4.PageA內容指向PageC,通過內部程序將內容C獲取到本地
5.PageA接收到PageC的數據后,將數據返回給http模塊
6.http模塊接收到數據后返回給瀏覽器
7.瀏覽器接收到http返回的html數據后,解析html的head
8.處理html的body
9.處理html的onload方法
10.瀏覽器最后將數據等顯示給用戶
注意:圖中不同斜線的區域
通過server跳轉后,用戶看到的是PageC的內容,但是瀏覽器地址欄中地址是PageA的地址。
優點:跳轉行為在server進行,一次tcp連接完成相關操作,對用戶是透明的,不會造成疑惑。
缺點:對用戶隱藏了信息,跳轉行為都發生在server端,對server有壓力。
server端功能各異,需要分工負責,當用戶訪問某功能后,需要返回另外一個功能,這個時候沒必要把全部功能都放到一個服務器上。
例如:單點登錄:用戶在某個服務器上登錄成功后,一定要在重新跳轉到功能服務器上。
網絡支付:用戶在銀行的網站支付完成后,必須重新定向到另外企業應用服務器上。
適用范圍:應用內部系統,適當的包含關系時。
http跳轉是指server根據工作情況通過http返回狀態碼,指示客戶端瀏覽器跳轉到相應頁面的過程,一般返回碼是302,下面是http302跳轉的相關參考流程
注意圖中,區域,顏色,斜線等等。
如上圖,用戶請求訪問PageB,頁面B內容指向頁面C,相關過程如下:
1.用戶通過瀏覽器訪問PageB
2.瀏覽器通過http處理模塊請求GetPageB
3.http處理模塊同服務器建立tcp連接,并發出請求獲取PageB
4.PageB內容指向PageC,PageB的處理模塊通過http的重定向協議通知客戶端程序,通過發送消息,302,以及跳到目的地址等進行
5.http處理模塊接收到消息后直接跳轉到目標地址,同時通知瀏覽器(修改地址欄)
6.http處理模塊請求PageC頁面內容
7.PageC處理模塊處理數據,生成html代碼,返回數據給http處理模塊
8.http處理模塊接收到數據后放回數據給瀏覽器
9.瀏覽器接收到http返回的html數據后,解析html的head
10.處理html的body
11.處理html的onload方法
12.瀏覽器最后將數據等顯示給用戶
優點:響應速度快,在http1.1協議下通過合適的設置可以使用同一個tcp連接,節省網絡時間,服務器及用戶端都不需要進行額外的數據處理工作,節省時間。
缺點:僅僅能做跳轉沒有其他功能,基于js及html的跳轉可以選擇延時跳轉,但是302無法選擇延時跳轉等
適用范圍:快速跳轉,不需要延時,經常用在兩個系統之間跳轉等。
通過在htmlhead中添加<meta>標簽,在標簽里指定相關參數,指示瀏覽器跳轉到相應頁面,相關跳轉必須在http層面將html數據傳輸給瀏覽器后,瀏覽器解釋html代碼過程中,發現跳轉并且根據跳轉指令跳轉到相應頁面。
參考流程如下圖:
如上圖,用戶請求訪問PageB,頁面B內容指向頁面C,相關過程如下:
1.用戶通過瀏覽器訪問PageB
2.瀏覽器通過http處理模塊請求GetPageB
3.http處理模塊同服務器建立tcp連接并發出請求獲取PageB
4.PageB處理模塊處理數據,生成html代碼,最后將html通過http協議傳輸回去。
5.http后將數據放回給瀏覽器,瀏覽器開始處理html
6.瀏覽器首先會處理html的head部分,最后發現有跳轉的相關指令
7.瀏覽器根據跳轉指令,重新聯系http模塊,發出獲取PageC的指令
8.http通過tcp連接到服務器,獲取PageC內容,然后返回給瀏覽器
9.瀏覽器接收到http返回的html數據后重新處理html,首先解析html的head
10.處理html的body
11.處理html的onload方法
12.瀏覽器最后將數據等顯示給用戶
優點:跳轉方式靈活,可以指定延時跳轉等等
缺點:可能多次建立tcp連接,在低速網絡下效率更低,浪費客戶端的時間
最后來看一下js跳轉,工作中每個瀏覽器都有自己的js執行引擎,執行引擎根據js代碼,來動態調用瀏覽器進行跳轉,相關參考代碼如下:
<scriptlanguage=”javascript”type=”text/javascript”>
window.location.href=”login.jsp?backurl=”+window.location.href;
</script>
具體js跳轉過程如下圖:
如上圖,用戶請求訪問PageB,頁面B內容指向頁面C,相關過程如下:
1.用戶通過瀏覽器訪問PageB
2.瀏覽器通過http處理模塊請求GetPageB
3.http處理模塊同服務器建立tcp連接同server建立連接,并發出請求獲取PageB
4.PageB處理模塊處理數據,生成html代碼,最后將html通過http協議傳輸回去。
5.http后將數據放回給瀏覽器,瀏覽器開始處理html
6.瀏覽器首先會處理html的head部分,最后會發現有跳轉的相關指令
7.瀏覽器處理html的body,以及js等,最后根據js的指令指示瀏覽器獲取頁面C
8.最后根據js的指令指示瀏覽器獲取頁面C瀏覽器會根據跳轉指令,重新聯系http模塊,發出獲取PageC的指令
9.http通過tcp連接到服務器,最后獲取PageC的內容,然后返回給瀏覽器
10.瀏覽器接收到http返回的html數據后重新處理html,首先解析html的head
11.處理html的body
12.處理html的onload方法
13.瀏覽器最后將數據等顯示給用戶
優點:跳轉方式靈活,可以指定延時跳轉等等。
缺點:可能多次建立tcp連接,在低速網絡下效率更低,浪費客戶端的時間。
使用訪問:快速跳轉,不需要延時,經常用在兩個系統之間跳轉等。
當A跳轉到B時,我們用符號A–>B表示,下面的循環跳轉A–>B–>C–>A,會發生什么事情。若是循環跳轉僅僅發生在server端,則相關系統會迅速被拖垮。若是循環跳轉發生在客戶端參與的系統中,很快客戶端及server端都會發生問題。
因此循環跳轉我們是要嚴格避免的,解決辦法:
1.不跳轉,但是不可能完全避免,并且不太可能實現,一般系統都是開放的系統,會不斷添加功能,即使當前沒有跳轉,但是過幾個月。。。。。。
2.打破跳轉的循環,加強系統的檢查力度避免循環跳轉的發生。
3.最重要的,監控系統,當發現某個客戶端或者系統在單位時間內有過多的訪問時,主動斷開連接或者拒絕這個客戶端的訪問等等。這個非常重要,一個好的系統是必須有這個功能的,否則即使沒有循環跳轉,但是若是用戶連續快速訪問一個頁面也是有很大問題的,例如ie中按下F5鍵循環刷新頁面,若是沒有檢測機制。。。。
每種跳轉方法對于用戶來講都帶來了內容上的變化,原以為A頁面的內容變成C頁面內容。跳轉的方法有很多,夜島SEO無法為大家一一列舉,當我們使用時如何選擇那種類別時,需要弄明白每一種跳轉的特點,包括:性能,功能等,根據不同網絡情況進行不同的選擇,例如有的網絡建立tcp連接速度慢,這個時候就適宜選擇server端的跳轉等。
若是保證系統之間的耦合關系更小,系統之間更靈活則需要采用http方式跳轉、js跳轉,html跳轉等。
有的時候需要在跳轉前進行一些判斷或者額外的操作等,就是js跳轉比較方便,但是也有個瀏覽器適配的問題。有時候一個js兼容性不好的js代碼可能不工作,造成部分用戶無法跳轉。
更多黑帽SEO技術知識學習教程請訪問夜島SEO技術博客(www.yeadao.com),一個專注于黑帽SEO快速排名技術研究與學習教程分享的網站!
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>index.jsp</title>
</head>
<body>
<a href="${pageContext.request.contextPath}/data.action?name=餃子">攜帶數據進行頁面跳轉</a>
</body>
</html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>main.jsp</title>
</head>
<body>
<h2>顯示頁面跳轉時攜帶的數據......</h2>
<!-- 在經過頁面跳轉后,在跳轉到的頁面里,嘗試獲取之前存放的數據-->
request: ${requestUser}<br>
httpSession: ${sessionUser}<br>
model: ${modelUser}<br>
map: ${mapUser}<br>
modelMap: ${modelMapUser}<br>
<!-- 嘗試直接獲取請求地址中攜帶的參數數據-->
param: ${param.name}
</body>
</html>
package com.example.controller;
import com.example.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Map;
@Controller
public class DataAction {
@RequestMapping("/data")
//這幾個參數都是SpringMVC內置的,可以直接聲明使用
public String data(HttpServletRequest request, HttpSession httpSession, Model model, Map<Object, Object> map, ModelMap modelMap){
//User實體類含有兩個屬性:name(String), age(int)。無參構造方法。全屬性的有參構造方法,getter,setter,toString方法
User user = new User("荷包蛋", 20);
//將user對象利用各SpringMVC內置對象存放到相應作用域中
request.setAttribute("requestUser", user);
httpSession.setAttribute("sessionUser", user);
model.addAttribute("modelUser", user);
map.put("mapUser", user);
modelMap.addAttribute("modelMapUser", user);
//最后完成頁面轉發跳轉
return "main";
}
}
package com.example.controller;
import com.example.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Map;
@Controller
public class DataAction {
@RequestMapping("/data")
public String data(HttpServletRequest request, HttpSession httpSession, Model model, Map<Object, Object> map, ModelMap modelMap){
User user = new User("荷包蛋", 20);
request.setAttribute("requestUser", user);
httpSession.setAttribute("sessionUser", user);
model.addAttribute("modelUser", user);
map.put("mapUser", user);
modelMap.addAttribute("modelMapUser", user);
//最后完成頁面的重定向跳轉
return "redirect:/admin/main.jsp";
}
}
目中經常會出現點擊跳轉錨點的方法,比如給一個a標簽一個href=“#錨點”,然后要跳的錨點給個id=“錨點”,這樣就實現簡單的跳轉,但是這樣在url地址欄后面都會出現一個諸如www.csdn.net#錨點,然后你點擊給一次后退都是退回上一個選擇的錨點url,這里總結一些跳轉錨點的方法。
<!DOCTYPE html>
<html>
<head>
<style>
div {
height: 800px;
width: 400px;
border: 2px solid black;
}
h2 {
position: fixed;
margin:50px 500px;
}
</style>
</head>
<body>
<h2>
<a href="#div1">to div1</a>
<a href="#div2">to div2</a>
<a href="#div3">to div3</a>
</h2>
<div id="div1">div1</div>
<div id="div2">div2</div>
<div id="div3">div3</div>
</body>
</html>
這種方法的缺點是點擊錨點之后,瀏覽器的URL會發生變化,如果刷新可能會出現問題。
<script type="text/javascript" src="http://code.jquery.com/jquery-1.8.0.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$("#div1Link").click(function() {
$("html, body").animate({
scrollTop: $("#div1").offset().top }, {duration: 500,easing: "swing"});
return false;
});
$("#div2Link").click(function() {
$("html, body").animate({
scrollTop: $("#div2").offset().top }, {duration: 500,easing: "swing"});
return false;
});
$("#div3Link").click(function() {
$("html, body").animate({
scrollTop: $("#div3").offset().top }, {duration: 500,easing: "swing"});
return false;
});
});
</script>
注意:運行上面的腳本的之前,先將為錨點增加相應的id,同時去掉href屬性。
$("html, body")可以替換為響應的div,如果不起作用,試著給該div增加overflow:scroll屬性。
另外,腳本可以進一步優化,自己來試試
這樣做的好處是:URL地址不會變,同時點擊錨點時會自動響應scroll事件,不需要重新綁定。
缺點是:如果頁面復雜的話,偏移值可能會發生變化需要算法輔助。
document.getElementById("divId").scrollIntoView();
比如:
document.querySelector("#roll1").onclick = function(){
document.querySelector("#roll1_top").scrollIntoView(true);
}
這里就是點擊id是#roll1的元素可以滾動到id是#roll1_top的地方,這里的#roll1和#roll1_top最好是一一對應的,
這種方法的好處,是URL不會變,同時能夠響應相應的scroll事件,不需要算法什么的。代碼如下:
<html>
<head>
<title>HTML5_ScrollInToView方法</title>
<meta charset="utf-8">
<script type="text/javascript">
window.onload = function(){
/*
如果滾動頁面也是DOM沒有解決的一個問題。為了解決這個問題,瀏覽器實現了一下方法,
以方便開發人員如何更好的控制頁面的滾動。在各種專有方法中,HTML5選擇了scrollIntoView()
作為標準方法。
scrollIntoView()可以在所有的HTML元素上調用,通過滾動瀏覽器窗口或某個容器元素,
調用元素就可以出現在視窗中。如果給該方法傳入true作為參數,或者不傳入任何參數,那么
窗口滾動之后會讓調動元素頂部和視窗頂部盡可能齊平。如果傳入false作為參數,調用元素
會盡可能全部出現在視口中(可能的話,調用元素的底部會與視口的頂部齊平。)不過頂部
不一定齊平,例如:
//讓元素可見
document.forms[0].scrollIntoView();
當頁面發生變化時,一般會用這個方法來吸引用戶注意力。實際上,為某個元素設置焦點也
會導致瀏覽器滾動顯示獲得焦點的元素。
支持該方法的瀏覽器有 IE、Firefox、Safari和Opera。
*/
document.querySelector("#roll1").onclick = function(){
document.querySelector("#roll_top").scrollIntoView(false);
}
document.querySelector("#roll2").onclick = function(){
document.querySelector("#roll_top").scrollIntoView(true);
}
}
</script>
<style type="text/css">
#myDiv{
height:900px;
background-color:gray;
}
#roll_top{
height:900px;
background-color:green;
color:#FFF;
font-size:50px;
position:relative;
}
#bottom{
position:absolute;
display:block;
left;0;bottom:0;
}
</style>
</head>
<body>
<button id="roll1">scrollIntoView(false)</button>
<button id="roll2">scrollIntoView(true)</button>
<div id="myDiv"></div>
<div id="roll_top">
scrollIntoView(ture)元素上邊框與視窗頂部齊平
<span id="bottom">scrollIntoView(false)元素下邊框與視窗底部齊平</span>
</div>
</body>
</html>
個人建議使用第四種方法。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。