【问题标题】:HttpResponse StatusCode - Server cannot set status after HTTP headers have been sentHttpResponse StatusCode - 发送 HTTP 标头后服务器无法设置状态
【发布时间】:2016-08-27 06:10:54
【问题描述】:

我尝试设置响应的状态码,但每次出现异常:发送 HTTP 标头后服务器无法设置状态。我附上了我的部分代码,我尝试了各种解决方案来解决这个问题,但没有成功。感谢您的帮助。

public class Custom404Page : Sitecore.Pipelines.HttpRequest.ExecuteRequest
{
    protected override void RedirectOnItemNotFound(string url)
    {
        try
        {
            SiteContext siteContext = Context.Site;
            Database database = Context.Database;
            RedirectTo404Page(siteContext, database);
        }
        catch (Exception ex)
        {
            LogManager.LogError(string.Format("Custom404Page throws exception. Redirection from {0} to custom 404 page failed.", url), ex);
        }
    }

    public void RedirectTo404Page(SiteContext siteContext, Database database)
    {
        try
        {
            if (String.IsNullOrEmpty(siteContext.StartPath))
            {
                return;
            }

            var startPage = database.GetItem(siteContext.StartPath);

            var paths = startPage.Paths;

            var parentPath = paths.ParentPath;

            var templateId = Page404Item.TemplateId;

            Item page404Item = database.SelectSingleItem("fast:/" + parentPath + "//*[@@templateid = '" + templateId + "']");

            if (page404Item != null)
            {
                if (page404Item.Versions.Count == 0)
                {
                    Language contentLanguage;
                    if (Language.TryParse(siteContext.Language, out contentLanguage))
                    {
                        Context.Language = contentLanguage;
                        page404Item = page404Item.Database.GetItem(page404Item.ID);
                    }
                }

                if (0 < page404Item.Versions.Count)
                {
                    string page404Url = GetUrlFromPage404Item(page404Item);
                    if (!string.IsNullOrEmpty(page404Url))
                    {
                        var context = HttpContext.Current;

                        context.Response.Clear();
                        context.Server.ClearError();

                        context.Response.BufferOutput = true;
                        context.Response.TrySkipIisCustomErrors = true;
                        context.Response.StatusCode = (int)HttpStatusCode.NotFound;

                        string html404Page = WebUtil.ExecuteWebPage(page404Url);
                        context.Response.Write(html404Page);

                        context.Response.Flush();
                        context.Response.SuppressContent = true;
                        context.ApplicationInstance.CompleteRequest();
                    }
                }
            }
        }
        catch (ThreadAbortException ex)
        {
        }
        catch (WebException ex)
        {
            LogManager.LogError(string.Format("Page404Provider throws WebException."), ex);
        }
        catch (Exception ex)
        {
            LogManager.LogError(string.Format("Page404Provider throws exception."), ex);
        }
    }

    private string GetUrlFromPage404Item(Item page404Item)
    {
        string url = string.Empty;

        Page404Item data = (Page404Item)page404Item;
        if (data.LinkTo404Page != null)
        {
            url = ItemUtility.CreateItemUrl(data.LinkTo404Page.Item, true);
        }

        return url;
    }
}

【问题讨论】:

  • 如果在使用Response.Write()之前设置StatusCode会怎样?
  • 同样的问题。它没有帮助。
  • 你有没有试过先做一个context.Response.Clear();
  • 我进行了更深入的测试,这也没有帮助。
  • 您显然已经在此处向我们展示的代码之前添加了输出。

标签: c# asp.net sitecore


【解决方案1】:

你只需要在ItemResolver之后添加一个补丁来处理找不到的项目。

配置:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
    <sitecore>
        <settings>
            <!-- ID of the page that will be displayed when the requested url does not resolve to an actual page -->
            <setting name="Namespace.PageNotFound.ID" value="{017424DE-DB4F-4D9E-9AA1-5326527CC6A3}" />
        </settings>
        <pipelines>
            <httpRequestBegin>
                <processor type="Namespace.Global.Pipeline.Custom.Custom404Resolver, Namespace.Global" patch:after="processor[@type='Sitecore.Pipelines.HttpRequest.ItemResolver, Sitecore.Kernel']" />
            </httpRequestBegin>
      <preprocessRequest help="Processors should derive from Sitecore.Pipelines.PreprocessRequest.PreprocessRequestProcessor">
        <processor type="Sitecore.Pipelines.PreprocessRequest.FilterUrlExtensions, Sitecore.Kernel">
          <param desc="Allowed extensions (comma separated)">*</param>
          <param desc="Blocked extensions (comma separated)">woff,eot,ttf,svg,gif,png,ico,jpg,jpeg,js,css</param>
          <param desc="Blocked extensions that stream files (comma separated)">*</param>
          <param desc="Blocked extensions that do not stream files (comma separated)"></param>
        </processor>
      </preprocessRequest>
    </pipelines>
    </sitecore>
</configuration>

处理器:

public class Custom404Resolver : HttpRequestProcessor
{
    public override void Process(HttpRequestArgs args)
    {
        Assert.ArgumentNotNull(args, "args");

        // Do nothing if the item is actually found
        if (Sitecore.Context.Item != null || Sitecore.Context.Database == null)
            return;

        // all the icons and media library items for the sitecore client need to be ignored
        if (args.Url.FilePath.StartsWith("/-/"))
            return;

        // Get the page not found item in Sitecore.

        var notFoundPagePath = Sitecore.IO.FileUtil.MakePath(Sitecore.Context.Site.StartPath, "Errors/page-not-found");
        var notFoundPage = Sitecore.Context.Database.GetItem(notFoundPagePath);

        if (notFoundPage == null)
        { 
            var notFoundPageId = Sitecore.Configuration.Settings.GetSetting("Namespace.PageNotFound.ID", "{017424DE-DB4F-4D9E-9AA1-5326527CC6A3}");
            notFoundPage = Sitecore.Context.Database.GetItem(notFoundPageId);
        }
        if (notFoundPage == null)
            return;

        // Switch to the 404 item
        Sitecore.Context.Item = notFoundPage;
    }
}

用于在 sitecore 中的“404”页面上进行渲染的控制器:

public class ErrorController : BaseController
{
    public ActionResult PageNotFound()
    {
        Response.StatusDescription = "Page not found";
        Response.StatusCode = (int)HttpStatusCode.NotFound;
        Response.TrySkipIisCustomErrors = true;

        return Content(string.Empty);
    }
}

创建一个使用此操作的控制器渲染并将其放置在发生 404 时将显示的 sitecore 页面的演示详细信息中。 此过程将保留 url,但显示 404 页面内容以及相应的 404 状态代码。

【讨论】:

  • 使用 RedirectPermanent 方法会是一个很好的解决方案吗?然后只将 StatusCode 设置为 404,因为作为我认为它有效的众多解决方案之一?作为我的解决方案之一,我尝试将 Context.Item 直接设置为我的 404 项目,但它不起作用。我正在使用网络表单。
  • 控制器渲染也可以通过子布局作为 webforms 用户控件来完成。 RedirectPermanent 将设置状态代码 301(永久移动),如果请求的 url 现在由不同的 url 提供服务,则该状态代码是合适的。您的问题是关于无法找到的项目,需要 404 代码。实际上,将上下文项分配给提供 404 内容的页面确实有效,就像我一直这样做一样。也许您在 httpRequestBegin 管道中有其他补丁? stackoverflow.com/questions/17517318/…
  • 谢谢大家。因此,正如您在上面描述的那样,我需要通过您的 ErrorController 中的子布局和代码创建用户控件,并将其分配给我在演示详细信息中的自定义 404 页面作为控件?我为此页面定义了 4 个控件(页眉、页脚等)。现在作为解决方案,我选择使用 Server.TransferRequest 方法。首先我的问题是关于 LayoutResolver 和处理没有为此定义布局的项目我想我可以使用 Server.TransferRequest() 因为项目存在但没有布局分配。然后我检查代码是否存在不存在的项目。
  • 有错误所以我决定修复它。越来越多的问题发生在带有标头的(ThreadAbortException)异常......并且Server.TransferRequest有效。但是对于不存在的项目,StatusCode 没有按照您的描述正确设置,它应该是 404。
  • 没有布局的项目不是页面,不应该单独提供,因此 301、404 等状态代码不适用。
猜你喜欢
  • 2014-01-27
  • 2011-01-23
  • 2015-11-07
  • 1970-01-01
  • 2019-07-22
  • 2015-06-24
  • 2015-05-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多