Назад | Перейти на главную страницу

Как 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, но проблема все еще существует.

У меня есть кое-что, что работает на 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);
            }
        }
    }
}