Как ReportManager может использовать внешний порт, отличный от брандмауэра?
Я на SSRS 2012 в основном режиме. Конфигурация, похоже, не сильно изменилась по сравнению с SSRS 2008, с которого я обновился, поэтому проблема относится к обеим версиям (однако, если есть решение, оно может относиться или не относиться к обеим).
Я нахожусь в ситуации, когда мне бы хотелось обслуживать веб-сайт ReportManager с одного набора портов на внешней стороне брандмауэра, но внутренне настроить SSRS на другом порту. Кто-нибудь знает, как это можно сделать?
подробности
Причина этого заключается в том, что код SSRS настаивает на создании полных, абсолютных URL-адресов для различных местоположений на веб-сайте ReportManager. (IMO, это только один из многих существенных / вредных недостатков дизайна в SSRS) Если бы он просто использовал URL-адреса, которые не пытались указать домен + порт, это не было бы проблемой.
пример
Давайте начнем с внешнего URL-адреса " http://reports.example.com/ssrs ", и ReportManager настроен для работы на порту 8080 (конечно, ваш порт переходит с порта 80 на 8088). Если вы перейдете на внешний URL, вы попадете на сайт просто отлично; давайте проигнорируем подсистему AuthC и предположим, что вы вошли в систему ОК. Теперь для некоторых ссылок (например, "Просмотр сведений", "Переместить", "Удалить" и т. Д.) Вы не пойдете туда, где ожидали, потому что SSRS пытается отправить вас по адресу " http://reports.example.com:8080/ssrs/... ". Вы можете вручную исправить ссылку, удалив порт, и вы попадете на страницу. Существуют различия в том, какие URL нарушены между SSRS 2012 и SSRS 2008, но проблема все еще остается.
1 ответ
У меня есть кое-что, что работает на SSRS 2012, но это полный взлом. Можно использовать клиентский Javascript для перезаписи всех URL-адресов (плюс случайный параметр RedirectUrl, который любит SSRS), но это не учитывает вызовы Response.Redirect() на стороне сервера. Так что вы останетесь с частичным решением.
Короче говоря, добавьте HttpModule в ReportManager, чтобы вы могли добавить обработчик события 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);
}
}
}
}