IIS7 przesłania customErrors podczas ustawiania Response.StatusCode?

98

Mam tutaj dziwny problem. Wszyscy wiedzą, że jeśli używasz customErrorssekcji web.config do tworzenia niestandardowej strony błędu, powinieneś ustawić ją Response.StatusCodena wszystko, co jest odpowiednie. Na przykład, jeśli utworzę niestandardową stronę 404 i nadam jej nazwę 404.aspx, mógłbym umieścić <% Response.StatusCode = 404 %>w treści, aby miała prawdziwy nagłówek stanu 404.

Śledź mnie tak daleko? Dobry. Teraz spróbuj to zrobić w IIS7. Nie mogę zmusić go do pracy, kropka. Jeśli Response.StatusCodejest ustawiona na niestandardowej stronie błędu, wydaje się, że usługi IIS7 całkowicie zastępują niestandardową stronę błędu i wyświetlają własną stronę stanu (jeśli została skonfigurowana).

Czy ktoś inny widział to zachowanie i może też wie, jak je obejść? Działał pod IIS6, więc nie wiem, dlaczego coś się zmieniło.

Uwaga: To nie to samo, co problem w niestandardowym 404 ASP.NET zwraca 200 OK zamiast 404 nie znaleziono

Mikołaja
źródło
Miałem to samo pytanie. Odpowiedziałem już tutaj http://stackoverflow.com/questions/347281/asp-net-custom-404-returning-200-ok-instead-of-404-not-found .
Bobby Cannon
Bobby, znalazłem to pytanie i spróbowałem, ale to nie rozwiązało problemu. Ale dzięki.
Nicholas,
Chciałbym skomentować, że ten problem występuje również podczas przełączania z Classic na Integrated Pipeine. Użyłem rozwiązania @PavelChuchuva (działa również rozwiązanie @RickStrahl). Domyślam się, że "przekazanie" w klasycznym jest automatyczne, w zintegrowanym pobiera globalną obsługę stron błędów serwera ..
sonjz

Odpowiedzi:

116

Ustaw existingResponse na PassThrough w sekcji system.webServer / httpErrors:

  <system.webServer>
    <httpErrors existingResponse="PassThrough" />
  </system.webServer>

Domyślna wartość właściwości existingResponse to Auto:

Auto mówi niestandardowemu modułowi błędów, aby zrobił właściwą rzecz. Rzeczywisty tekst błędu widziany przez klientów będzie miał wpływ w zależności od wartości fTrySkipCustomErrors zwróconej w IHttpResponse::GetStatuswywołaniu. Gdy fTrySkipCustomErrors jest ustawiona na true, niestandardowy moduł błędu przepuści odpowiedź, ale jeśli jest ustawiony na false, moduł niestandardowych błędów zastępuje tekst własnym tekstem.

Więcej informacji: Czego można oczekiwać od niestandardowego modułu błędów usług IIS7

Pavel Chuchuva
źródło
3
Zauważ, że ustawienie existingResponse na PassThrough może prowadzić do pewnych efektów ubocznych. Przed wprowadzeniem jakichkolwiek zmian skorzystaj z łącza udostępnionego przez Pawła.
Lex Li
Jest <httpErrors existingResponse="PassThrough" />równoważne Response.TrySkipIisCustomErrorslub czy zachowują się inaczej?
Asbjørn Ulsberg
1
@sbjornu Osiągają to samo, ale dzięki temu Response.TrySkipIisCustomErrorszyskujesz lepszą kontrolę, kiedy wyświetlać niestandardowe błędy usług IIS.
Pavel Chuchuva
dziękuję, widziałem wiele informacji na temat odpowiedzi. tryskipiiscustomerrors, ale nie tak dużo na temat istniejącej odpowiedzi.
HBCondo
Rozwiązałem problem z niestandardowymi stronami błędów, które nie działały na moim hoście internetowym, na którym działa IIS7, po prostu ustawiając existingResponse = "Auto", co było bardzo zaskakujące, ponieważ artykuł, do którego odwołuje się, twierdzi, że jest to ustawienie domyślne. Najwyraźniej nie jest ... lub moja firma hostingowa ustawiła niewłaściwą wartość domyślną w innym miejscu, jak przypuszczam. Tak czy inaczej, mam nadzieję, że zaoszczędzi to komuś kilku godzin: \
Eric Sassaman
80

Najłatwiejszym sposobem na zachowanie spójności jest wyczyszczenie błędu i użycie elementu Response.TrySkipIisCustomErrors i ustawienie wartości true. Spowoduje to zastąpienie obsługi globalnej strony błędów usług IIS z poziomu Twojej strony lub globalnego modułu obsługi błędów w Application_Error.

Server.ClearError();
Response.TrySkipIisCustomErrors = true;

Zwykle należy to zrobić w programie obsługi Application_Error, który obsługuje wszystkie błędy, których nie wychwytują programy obsługi błędów aplikacji.

Bardziej szczegółowe informacje można znaleźć w tym poście na blogu: http://www.west-wind.com/weblog/posts/745738.aspx

Rick Strahl
źródło
2
To również nie działa dla mnie (IIS8), a rada wydaje się nie pasować do OP (zakładając, że czytam ją poprawnie). I chcącustomError skonfigurowane w pliku web.config na spuście. Z Response.TrySkipIisCustomErrors = truetym zachowaniem mam to samo: wyświetlana jest brzydka strona błędu generowana przez serwer. Po ustawieniu falsenic się nie dzieje - puste okno przeglądarki.
Shawn South
U mnie działało dobrze! Chociaż ustawienie, o którym wspomina Pavel Chuchuva w swojej odpowiedzi, również działało, miało pewne skutki uboczne, które spowodowały inne problemy. To ustawienie pozwala mi pominąć przesłonięcie błędu usług IIS w określonym scenariuszu, który chciałem, pozostawiając zachowanie nienaruszone dla wszystkiego innego.
Kevin Tighe
U mnie dobrze działało na platformie Azure. Nagłówki serweraServer:Microsoft-IIS/8.5 X-AspNet-Version:4.0.30319 X-AspNetMvc-Version:5.2 X-Powered-By:ASP.NET
oxfn
Nadal uważam, że muszę ustawić, customErrors mode="Off"aby to zadziałało. Jeśli to zrobię, wtedy httpErrors existingResponse = "Auto" (domyślnie) działa poprawnie, gdy używam kodu w tej odpowiedzi.
AaronLS
11

Rozwiązany: okazuje się, że opcja „Błędy szczegółowe” musi być włączona, aby usługi IIS7 mogły „przekazać” dowolną stronę błędu, którą możesz mieć. Zobacz http://forums.iis.net/t/1146653.aspx

Mikołaja
źródło
1
Chociaż ta została oznaczona jako odpowiedź, myślę, że warto przeczytać inne odpowiedzi, aby uzyskać więcej informacji na ten temat.
Lex Li
Dobrze byłoby również usunąć. HandleErrorAttribute w FilterConfig
Per G
4

Nie jestem pewien, czy ma to podobny charakter, czy nie, ale rozwiązałem problem, który z pozoru brzmi podobnie i oto jak sobie z tym poradziłem.

Przede wszystkim domyślna wartość dla existingResponse (Auto) była w moim przypadku poprawną odpowiedzią, ponieważ mam niestandardowe 404, 400 i 500 (mógłbym stworzyć inne, ale te trzy wystarczą do tego, co robię). Oto odpowiednie sekcje, które mi pomogły.

Z web.config:

<customErrors mode="Off" />

I

<httpErrors errorMode="Custom" existingResponse="Auto" defaultResponseMode="ExecuteURL">
  <clear />
  <error statusCode="404" path="/errors/404.aspx" responseMode="ExecuteURL" />
  <error statusCode="500" path="/errors/500.aspx" responseMode="ExecuteURL" />
  <error statusCode="400" path="/errors/400.aspx" responseMode="ExecuteURL" />
</httpErrors>

Stamtąd dodałem to do Application_Error na global.asax:

    Response.TrySkipIisCustomErrors = True

Na każdej z moich niestandardowych stron błędów musiałem podać poprawny kod statusu odpowiedzi. W moim przypadku używam niestandardowego 404 do wysyłania użytkowników do różnych sekcji mojej witryny, więc nie chcę, aby kod stanu 404 był zwracany, chyba że w rzeczywistości jest to martwa strona.

W każdym razie tak to zrobiłem. Mam nadzieję, że to komuś pomoże.

SEFL
źródło
3

Ten problem był poważnym bólem głowy. Żadna z wcześniej wymienionych sugestii nie rozwiązała tego problemu za mnie, więc dołączam moje rozwiązanie. Dla przypomnienia, nasze środowisko / platforma wykorzystuje:

  • .NET Framework 4
  • MVC 3
  • IIS8 (stacja robocza) i IIS7 (serwer WWW)

W szczególności próbowałem uzyskać odpowiedź HTTP 404, która przekierowała użytkownika na naszą niestandardową stronę 404 (za pośrednictwem ustawień Web.config).

Najpierw mój kod musiał wyrzucić plik HttpException. Zwrot NotFoundResultze sterownika nie przyniósł rezultatów, o które mi chodziło.

throw new HttpException(404, "There is no class with that subject");

Wtedy miałem do konfigurowania zarównocustomErrors i httpErrorwęzłów w pliku web.config.

<customErrors mode="On" defaultRedirect="/classes/Error.aspx">
  <error statusCode="404" redirect="/classes/404.html" />
</customErrors>

...

<httpErrors errorMode="Custom" existingResponse="Auto" defaultResponseMode="ExecuteURL">
  <clear />
  <error statusCode="404" path="/classes/404.aspx" responseMode="ExecuteURL" />
</httpErrors>

Zauważ, że zostawiłem existingResponseas Auto, który jest inny niż rozwiązanie dostarczone przez @sefl.

Te customErrorsustawienia wydawały się być konieczne do obsługi mojego wyraźnie wyrzucony HttpException, natomiast httpErrorswęzeł obsługiwane adresy URL, które wykraczały poza wzorców trasą określoną w Globals.asax.cs.

PS Z tymi ustawieniami nie musiałem ustawiać Response.TrySkipIisCustomErrors

Shawn South
źródło
2

TrySkipIisCustomErrorsjest tylko częścią układanki. Jeśli używasz niestandardowych stron błędów, ale chcesz również dostarczać treści zgodne z REST w oparciu o statusy 4xx, masz problem. Ustawienie httpErrors.existingResponse web.config na „Auto” nie działa, ponieważ .net wydaje się zawsze dostarczać jakąś zawartość strony do IIS, dlatego użycie „Auto” powoduje, że wszystkie (lub przynajmniej niektóre) niestandardowe strony błędów nie są używane. Użycie opcji „Zamień” też nie zadziała, ponieważ odpowiedź będzie zawierała kod stanu http, ale jej treść będzie pusta lub wypełniona niestandardową stroną błędu. A „PassThrough” w rzeczywistości wyłącza CEP, więc nie można go używać.

Więc jeśli chcesz ominąć CEP w niektórych przypadkach (omijając mam na myśli zwracanie statusu 4xx z pewną zawartością) będziesz potrzebować dodatkowego kroku: wyczyść błąd:

void Application_Error(object sender, EventArgs e)
{
    var httpException = Context.Server.GetLastError() as HttpException;
    var statusCode = httpException != null ? httpException.GetHttpCode() : (int)HttpStatusCode.InternalServerError;

    Context.Server.ClearError();
    Context.Response.StatusCode = statusCode;
}

Więc jeśli chcesz użyć odpowiedzi REST (tj. 400 - złe żądanie) i wysłać z nią jakąś zawartość, wystarczy ustawić TrySkipIisCustomErrorsgdzieś działanie i ustawić existingResponsena „Auto” w sekcji httpErrors w web.config. Teraz:

  • gdy nie ma błędu (akcja zwraca 4xx lub 5xx) i zwracana jest część treści, CEP nie jest używany i treść jest przekazywana do klienta;
  • gdy wystąpi błąd (zostanie zgłoszony wyjątek), zawartość zwrócona przez procedury obsługi błędów jest usuwana, więc używany jest CEP.

Jeśli chcesz zwrócić status z pustą treścią z twojej akcji, zostanie to potraktowane jako pusta odpowiedź i zostanie wyświetlony CEP, więc jest trochę miejsca na ulepszenie tego kodu.

Łukasƨ Fronczyk
źródło
0

Domyślnie IIS 7 używa szczegółowych niestandardowych komunikatów o błędach, więc zakładam, że Response.StatusCode będzie równy 404.XX, a nie tylko 404.

Można skonfigurować usługi IIS7 do korzystania z prostszych kodów komunikatów o błędach lub zmodyfikować kod obsługujący bardziej szczegółowe komunikaty o błędach oferowane przez usługi IIS7.

Więcej informacji można znaleźć tutaj: http://blogs.iis.net/rakkimk/archive/2008/10/03/iis7-eniring-custom-error-pages.aspx

Dalsze dochodzenie ujawniło, że pomyliłem się - szczegółowe komunikaty nie są domyślnie, ale być może zostały włączone na twoim pudełku, jeśli widzisz różne komunikaty o błędach, o których wspomniałeś.

nullnvoid
źródło
Response.StatusCode jest liczbą całkowitą, więc nie widzę sposobu na ustawienie bardziej szczegółowego kodu niż tylko „404”. Mam skonfigurowane usługi IIS7 do używania / wyświetlania niestandardowych stron błędów, takich jak wskazuje Twój adres URL.
Nicholas
Hmmm ... Niestety nie mogę w tej chwili przetestować, ponieważ nie mam komputera w domu. Jeśli do tego czasu nie masz rozwiązania - zajrzę dzisiaj wieczorem.
nullnvoid