我在本机模式下使用 SSRS 2012。配置似乎与我升级的 SSRS 2008 相比没有太大变化,因此该问题适用于两个版本(但是,如果有解决方案,它可能适用于或不适用于两者)。
我的情况是,我想从防火墙外部的一组端口提供 ReportManager 网站,但在内部,SSRS 安装在不同的端口上。有人知道如何实现吗?
细节
之所以会出现这个问题,是因为 SSRS 代码坚持要构建指向 ReportManager 网站内不同位置的完整、绝对 URL。(在我看来,这只是 SSRS 中许多重大/严重的设计缺陷之一)如果它只使用不尝试指定域+端口的 URL,那么这将不是问题。
例子
让我们从“http://reports.example.com/ssrs“,并且 ReportManager 配置为在端口 8080 上运行(当然,您的端口转发从端口 80 转到 8088)。如果您转到外部 URL,您将顺利访问该网站;让我们忽略 AuthC 子系统并假设您已成功登录。对于某些链接(例如“详细信息视图”、“移动”、“删除”等),现在,您不会到达您预期的位置,因为 SSRS 会尝试将您发送到“http://reports.example.com:8080/ssrs/......”。您可以通过删除端口来手动修复链接,然后您将进入该页面。SSRS 2012 和 SSRS 2008 之间损坏的 URL 有所不同,但问题仍然存在。
答案1
我有一些适用于 SSRS 2012 的方法,但这完全是黑客行为。可以使用客户端 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);
}
}
}
}