ReportManager 如何在外部使用與防火牆後面不同的埠?
我在本機模式下使用 SSRS 2012。配置似乎與我升級的 SSRS 2008 相比沒有太大變化,因此該問題適用於兩個版本(但是,如果有解決方案,它可能適用於也可能不適用於兩個版本)。
我的情況是,我想從防火牆外部的一組埠提供 ReportManager 網站,但在內部,在不同的埠上設置了 SSRS。有誰知道如何做到這一點?
細節
這是一個問題的原因是因為 SSRS 程式碼堅持建構到 ReportManager 網站內不同位置的完整、絕對 URL。(IMO,這只是 SSRS 中許多重大/嚴重的設計缺陷之一)如果它只使用沒有嘗試指定域+埠的 URL,這不會是一個問題。
例子
讓我們從“ http://reports.example.com/ssrs ”的外部 URL 開始,並且 ReportManager 被配置為使用埠 8080(當然,您的埠轉發從埠 80 到 8088)。如果您訪問外部 URL,您會很好地訪問該站點;讓我們忽略 AuthC 子系統並假設您登錄正常。對於某些連結(例如“詳細資訊視圖”、“移動”、“刪除”等),現在您不會去您預期的地方,因為 SSRS 會嘗試將您發送到“ http://reports.example”。 com:8080/ssrs/ …"。您可以通過刪除埠手動修復連結,然後您將進入該頁面。SSRS 2012 和 SSRS 2008 之間破壞的 URL 存在差異,但問題仍然存在。
我有一些適用於 SSRS 2012 的東西,但它完全是 hack。可以使用客戶端 Javascript 重寫所有 URL(加上 SSRS 喜歡的偶爾的 RedirectUrl 參數),但這不考慮伺服器端的 Response.Redirect() 呼叫。因此,您將獲得部分解決方案。
簡而言之,向 ReportManager 添加一個 HttpModule,這樣您就可以添加一個 PreRequestHandlerExecute 事件處理程序。在其中,使用 Reflection 修復 GlobalApp.BaseUrl 和 Request.Url 以關閉 HOST 標頭而不是預設標頭。您必須更改兩者,因為 SSRS 在建構連結時並不總是使用自己的 BaseUrl。(我使用 ILSpy 來查找要更改的欄位。)
這是我的。我敢肯定它可以做得更好,但我有什麼作品,我真的不在乎了。在 SSRS 上工作有一種方式可以讓你失去生活的意願。
編輯:修復了修改 Request.Url 的部分。請注意,當它指定 .Fragment 時,客戶端不會發送它,因此它始終為空白。
void context_PreRequestHandlerExecute(object sender, EventArgs ea) { HttpApplication app = sender as HttpApplication; // also at: HttpContext.Current.ApplicationInstance string host = app.Context.Request.Headers["HOST"]; if (!string.IsNullOrEmpty(host)) { System.Reflection.FieldInfo fi = typeof(Microsoft.ReportingServices.UI.GlobalApp).GetField("m_baseUrl", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); if (fi != null) { string protocol = "http://"; if (app.Context.Request.IsSecureConnection) protocol = "https://"; Uri url = new Uri(string.Format("{0}{1}{2}", protocol, host, app.Context.Request.ApplicationPath)); fi.SetValue(app as Microsoft.ReportingServices.UI.GlobalApp, url); fi = typeof(System.Web.HttpRequest).GetField("_url", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); if (fi != null) { url = new Uri(string.Format("{0}{1}{2}{3}{4}", protocol, host, app.Context.Request.FilePath, app.Context.Request.Url.Query, app.Context.Request.Url.Fragment)); fi.SetValue(app.Context.Request, url); } } } }