CustomErrors не работает при установке redirectMode="ResponseRewrite"
На старом сайте я менял способ работы CustomErrors, добавляя redirectMode="ResponseRewrite"
(новое в 3.5 SP1):
<customErrors mode="RemoteOnly" defaultRedirect="Error.aspx" redirectMode="ResponseRewrite">
<error statusCode="404" redirect="404.aspx" />
</customErrors>
Дело в том, что он показывает мне общую страницу ошибок (ту, которую вы получаете, когда вы не устанавливаете customErrors
, Если я удалюredirectMode="ResponseRewrite"
часть работает нормально.
Я уверен, что 3.5 SP1 установлен на сервере, потому что я использую ту же настройку на других сайтах, размещенных на том же сервере.
Есть идеи?
9 ответов
Я обнаружил, что проблема была в Error.aspx. Все еще не могу найти, что было фактической ошибкой в error.aspx, который вызывает проблему.
Изменение страницы в статический HTML-файл решило проблему.
Для любого, кто пытается сделать это в приложении MVC, важно отметить, что ResponseRewrite
использования Server.Transfer
за кулисами. Следовательно defaultRedirect
должен соответствовать допустимому файлу в файловой системе. По-видимому, Server.Transfer
не совместим с маршрутами MVC, поэтому, если ваша страница ошибки обслуживается действием контроллера, Server.Transfer
будет искать / Ошибка / Что бы то ни было, не найти его в файловой системе и вернуть страницу с общей ошибкой 404!
Единственный способ, который отлично сработал для меня, это отключить пользовательские ошибки и заменить страницы ошибок iis через web.config. Он отправляет правильный код состояния с ответом и имеет преимущество, что он не проходит через mvc.
вот код
Отключить пользовательские ошибки
<customErrors mode="Off" />
Заменить страницы ошибок
<httpErrors errorMode="Custom" existingResponse="Replace"> <remove statusCode="404" subStatusCode="-1" /> <remove statusCode="500" subStatusCode="-1" /> <error statusCode="404" path="Error404.html" responseMode="File" /> <error statusCode="500" path="Error.html" responseMode="File" /> </httpErrors>
Заметка. использование responsemode="file"
если URL является прямой ссылкой на файл
информация: http://tipila.com/tips/use-custom-error-pages-aspnet-mvc
Происходит то, что IIS просматривает код состояния ошибки и представляет свою страницу ошибок вместо вашей. Чтобы решить эту проблему, необходимо установить это в коде за страницей страницы с ошибкой, чтобы IIS не делал это:
Response.TrySkipIisCustomErrors = true;
Это будет работать только в IIS7 или выше, для более ранних версий IIS вам нужно будет поиграть с настройками страницы ошибок.
Из-за опоры на Server.Transfer
кажется, что внутренняя реализация ResponseRewrite
не совместим с MVC.
Мне кажется, это явная дыра в функциональности, поэтому я решил повторно реализовать эту функцию с помощью модуля HTTP, чтобы она просто работала. Приведенное ниже решение позволяет обрабатывать ошибки, перенаправляя их на любой действительный маршрут MVC (включая физические файлы), как вы это обычно делаете.
<customErrors mode="RemoteOnly" redirectMode="ResponseRewrite">
<error statusCode="404" redirect="404.aspx" />
<error statusCode="500" redirect="~/MVCErrorPage" />
</customErrors>
Это было проверено на следующих платформах;
- MVC4 в режиме интегрированного конвейера (IIS Express 8)
- MVC4 в классическом режиме (VS Development Server, Cassini)
- MVC4 в классическом режиме (IIS6)
namespace Foo.Bar.Modules {
/// <summary>
/// Enables support for CustomErrors ResponseRewrite mode in MVC.
/// </summary>
public class ErrorHandler : IHttpModule {
private HttpContext HttpContext { get { return HttpContext.Current; } }
private CustomErrorsSection CustomErrors { get; set; }
public void Init(HttpApplication application) {
System.Configuration.Configuration configuration = WebConfigurationManager.OpenWebConfiguration("~");
CustomErrors = (CustomErrorsSection)configuration.GetSection("system.web/customErrors");
application.EndRequest += Application_EndRequest;
}
protected void Application_EndRequest(object sender, EventArgs e) {
// only handle rewrite mode, ignore redirect configuration (if it ain't broke don't re-implement it)
if (CustomErrors.RedirectMode == CustomErrorsRedirectMode.ResponseRewrite && HttpContext.IsCustomErrorEnabled) {
int statusCode = HttpContext.Response.StatusCode;
// if this request has thrown an exception then find the real status code
Exception exception = HttpContext.Error;
if (exception != null) {
// set default error status code for application exceptions
statusCode = (int)HttpStatusCode.InternalServerError;
}
HttpException httpException = exception as HttpException;
if (httpException != null) {
statusCode = httpException.GetHttpCode();
}
if ((HttpStatusCode)statusCode != HttpStatusCode.OK) {
Dictionary<int, string> errorPaths = new Dictionary<int, string>();
foreach (CustomError error in CustomErrors.Errors) {
errorPaths.Add(error.StatusCode, error.Redirect);
}
// find a custom error path for this status code
if (errorPaths.Keys.Contains(statusCode)) {
string url = errorPaths[statusCode];
// avoid circular redirects
if (!HttpContext.Request.Url.AbsolutePath.Equals(VirtualPathUtility.ToAbsolute(url))) {
HttpContext.Response.Clear();
HttpContext.Response.TrySkipIisCustomErrors = true;
HttpContext.Server.ClearError();
// do the redirect here
if (HttpRuntime.UsingIntegratedPipeline) {
HttpContext.Server.TransferRequest(url, true);
}
else {
HttpContext.RewritePath(url, false);
IHttpHandler httpHandler = new MvcHttpHandler();
httpHandler.ProcessRequest(HttpContext);
}
// return the original status code to the client
// (this won't work in integrated pipleline mode)
HttpContext.Response.StatusCode = statusCode;
}
}
}
}
}
public void Dispose() {
}
}
}
использование
Включите это как последний HTTP-модуль в ваш web.config
<system.web>
<httpModules>
<add name="ErrorHandler" type="Foo.Bar.Modules.ErrorHandler" />
</httpModules>
</system.web>
<!-- IIS7+ -->
<system.webServer>
<modules>
<add name="ErrorHandler" type="Foo.Bar.Modules.ErrorHandler" />
</modules>
</system.webServer>
Я знаю, что этот вопрос немного устарел, но я подумал, что должен указать, что для его работы не требуется статический файл.
Я столкнулся с подобной вещью, и это просто вопрос обнаружения этой ошибки в вашем Error.aspx, в нашем случае это произошло потому, что используемая мастер-страница опиралась на часть данных сеанса, а когда был установлен ResponseRewrite, сеанс недоступен для наша страница Error.aspx.
Я еще не выяснил, связана ли эта недоступность сессий с нашей конкретной конфигурацией приложения или с "разработанной" частью ASP.net.
Согласно сообщению @Amila и подтверждению и завершению этого сообщения, у меня такая же проблема, я много копаю в Google, но у меня не было возможности найти правильный ответ. Проблема в том, когда вы работаете сASP.Net Web Application
, будь то MVC
или нет, вы не можете добиться пользовательской ошибки, используя старый способ с Webform project
.
Здесь вариант, если вы используетеASP.Net Web Application
(будь то MVC
или не):
В своих сценариях я просто хочу определить настраиваемую ошибку для конкретной ошибки 404. Другая ошибка определяется так же, как ошибка 404:
Senario1: Ваша настраиваемая страница - это простойHTML
файл и помещен в root
:
<configuration>
<system.web>
<customErrors mode="Off" />
</system.web>
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404" subStatusCode="-1" />
<error statusCode="404" path="ErrorPage.html" responseMode="File" />
</httpErrors>
</system.webServer>
</configuration>
Senario2: Ваша настраиваемая страница является
aspx
страницу и помещен в root
:<configuration>
<system.web>
<customErrors mode="Off" />
</system.web>
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404" subStatusCode="-1" />
<error statusCode="404" path="ErrorPage" responseMode="Redirect" />
</httpErrors>
</system.webServer>
</configuration>
Примечание. Я удаляю расширение aspx из-заRouteConfig.cs
в ASP.net application
, вы можете использовать ErrorPage.aspx
если хотите, это необязательно.
Senario3: Ваша настраиваемая страница является
aspx
страницу и помещен в [ex: Page folder in The root (~/Page/ErrorPage.aspx)]
:Совет, который я заметил, - НЕ СЛЕДУЕТ ИСПОЛЬЗОВАТЬ
~/
к корневой адресации; Так что я просто обращаюсь без~/
отметка:<configuration>
<system.web>
<customErrors mode="Off" />
</system.web>
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404" subStatusCode="-1" />
<error statusCode="404" path="Page/ErrorPage" responseMode="Redirect" />
</httpErrors>
</system.webServer>
</configuration>
Я построил страницу ошибок в aspx, которая передает запрос на контроллер ASP.NET MVC. Вы можете переписать запрос на эту страницу aspx, и он передаст запрос на ваш пользовательский контроллер.
protected void Page_Load(object sender, EventArgs e)
{
//Get status code
var queryStatusCode = Request.QueryString.Get("code");
int statusCode;
if (!int.TryParse(queryStatusCode, out statusCode))
{
var lastError = Server.GetLastError();
HttpException ex = lastError as HttpException;
statusCode = ex == null ? 500 : ex.GetHttpCode();
}
Response.StatusCode = statusCode;
// Execute a route
RouteData routeData = new RouteData();
string controllerName = Request.QueryString.Get("controller") ?? "Errors";
routeData.Values.Add("controller", controllerName);
routeData.Values.Add("action", Request.QueryString.Get("action") ?? "Index");
var requestContext = new RequestContext(new HttpContextWrapper(Context), routeData);
IController controller = ControllerBuilder.Current.GetControllerFactory().CreateController(requestContext, controllerName);
controller.Execute(requestContext);
}
Узнайте больше здесь: /questions/4074101/customerrors-protiv-httperrors-znachitelnyij-nedostatok-dizajna/4074109#4074109
Я обнаружил, что если вы используете redirectMode="ResponseRewrite", то вам нужно что-то добавить в область перезаписи файла web.config. Проблема в том, когда ваш сайт не работает! Вы не можете переписать URL, так как ваш сайт не может вызвать "virtual.aspx", который обрабатывает ваше переписывание!
В моем конкретном случае моя страница с ошибкой имела главную страницу с пользовательским элементом управления, который пытался использовать Session. Если Session недоступен, вы получаете HttpException: "Состояние Session может использоваться только в том случае, если для enableSessionState задано значение true, либо в файле конфигурации, либо в директиве Page". Самое простое решение - перейти на статический html, второе самое простое - использовать более простую страницу с ошибкой, самое сложное - убедиться, что ваша страница с ошибками нигде не делает никаких предположений (например, Session, например, не сгенерирует исключение) и не может быть ошибка.