[原創]另一種思路固定URL及.NET實現

背景

項目經常有這樣的需求:爲了安全需要向用戶隱藏URL。

首先說明下這個需求如果是爲了安全則完全沒有理由,因為不可能隱藏了URL就安全了,對於瞭解一些HTTP原理的用戶,這個需求是掩耳盜鈴,當然隱藏後也並非沒有好處,起碼URL看上去乾淨整潔。其實也就是隱藏查詢字符串(QueryString),一些常見的做法如使用iFrame、URL重寫等,這裡就不討論了。

如果把以上需求變成爲了乾淨整潔,不妨把隱藏URL變成固定URL更好。那麼URL重寫就不滿足需求了。

 

知識

一般的HTTP請求,大多是GET和POST請求,GET請求不管你服務器端如何如何,客戶端的URL是一定會變的。POST請求則要看頁面Form的Action,URL會變成Action的頁面。一般<a>標籤直接設置href後,點擊直接執行GET請求,請求href中的資源,form.submit則是執行POST請求。

 

原理及實現

一、

  既然GET請求一定會改變URL,那麼我們不可能實現客戶端第一次發起GET請求時固定URL,因為這是客戶端事件,我們只能GET後重定向到某一我們需要固定的頁面。可是重定向後頁面應該呈現什麽內容呢?我的做法是截獲所有GET請求,將請求的URL記錄到一個FORM中的隱藏字段,Form.Action是一個固定的頁面(這個頁面完全可以不真實存在),然後直接提交Form,發出POST請求,這樣子用戶的URL就變成了固定頁面。服務器再截獲POST請求,取得Request中記錄的原GET請求的URL,通過重寫URL獲得真正的頁面內容。

.NET則是在Global.ascx中的 Application_BeginRequest實現截獲請求

GET請求的處理,直接寫response完全不需要有index.aspx頁面的存在:

 1 StringBuilder html = new StringBuilder();
2 html.Append("<form method=\"post\" id=\"form\">")
3 .AppendFormat("<input type=\"hidden\" name=\"__POSTURL\" value=\"{0}\" />", Request.AppRelativeCurrentExecutionFilePath + Request.Url.Query + Request.PathInfo)
4 .Append("</form>")
5 .Append("<script>")
6 .AppendFormat("form.action = \"{0}\"; form.submit();", Request.ApplicationPath.TrimEnd('/') + "/index.aspx")
7 .Append("</script").Append(">");
8 Response.Clear();
9 Response.Write(html);
10 Response.End();

POST請求的處理,注意false參數固定了引用的url,沒有此參數會導致跨目錄頁面的stylesheet路徑不對而失效。

1 HttpContext.Current.RewritePath(Request["__POSTURL"], false);


二、

  實現了以上代碼後,在頁面中做POST請求,仍然會POST到原頁面,URL會變。這裡通過修改Form.Action實現POST到同一頁面,使用隱藏域記錄真正需要POST到的頁面,然後使用到前面POST請求的重寫URL而POST到隱藏域頁面。

實現:在MasterPage(或者你的BasePage頁面)的Page_Load中:

1 string actionUrl = Request.ApplicationPath.TrimEnd('/') + "/index.aspx";
2 string postUrl = Page.AppRelativeVirtualPath + Request.Url.Query + Request.PathInfo;
3 Page.Form.Action = actionUrl;
4 Page.ClientScript.RegisterHiddenField("__POSTURL", postUrl)

注意POSTURL一定要是相對路徑如“~/xxx/xxx.aspx”,因為RewritePath方法需要傳入相對路徑。

 

三、

  以上已經實現了對GET和POST的固定URL處理,但是頁面中的超鏈接如果是直接GET,難免URL會閃動後變回固定URL,要避免這個只能通過項目要求不能直接使用簡單的GET跳轉(包括服務器端的Response.Redirect)。

不用GET跳轉而用一個簡單特殊的POST跳轉,則完全可以做到URL紋絲不動,在需要跳轉的按鈕或者鏈接註冊.click事件:

function postRedirect(url) {
$("body").append('<form id="postForm" method="post" action="index.aspx"><input type="hidden" name="__POSTURL" value="' + url + '" /></form>');
$("#postForm").submit();
}

以上只是一個簡單的例子,並不通用,需要注意、改善的地方有action的路徑,阻止控件的自身事件(preventDefault)阻止冒泡等,你也可以擴展傳入參數,通過隱藏域傳到要POST的頁面。

後臺跳轉的話也可以模仿此JS方法或模仿截獲GET請求的那段代碼寫通用方法即可。也可以使用Server.Transefer等方式(未驗證)。

 

以上方案可能存在一些問題,比如若使用了PostBackUrl則會失效,但解決方式也很簡單,比如提交前再更改form的action,直接使用自己擴展加了參數後的postRedirect做跨頁面提交而不使用PostBackUrl。本文也主要是提供另一個自己想到的思路,具體實現起來可能會有更好的方法。

2012-1-10 補充:Response.Redirect處理

服務器端使用Response.Redirect實際上就是向客戶端發送301或302跳轉響應,只要在EndRequest中攔截此Response并改成偽Post Form作為跳轉用途,再將StatusCode改成200(重要)即可。



posted on 2011-12-29 16:19    阅读(766)  评论(0编辑  收藏  举报