c# - 如何删除每个响应上的一些 httpresponse header (例如 Server 和 ETag)?

标签 c# asp.net-mvc asp.net-core

Using IIS 8 we can remove the ETag header by conf但是如果我们使用 kestrel 或其他服务器实现该怎么办?

在 ASP.Net 中,4 我使用了 global.asax 的 PreSendRequestHeaders 事件:

    protected void Application_PreSendRequestHeaders(object sender, EventArgs e)
    {
        if (HttpContext.Current != null)
        {
            HttpContext.Current.Response.Headers.Remove("Server");
            HttpContext.Current.Response.Headers.Remove("ETag");
        }
    }

[更新]

我尝试使用 IHttpResponseFeature 的 OnSendHeaders 但这并不在所有情况下都有效,特别是对于静态文件中间件

最佳答案

我所做的是一个中间件来覆盖httpcontext

public class RemoveResponseHeadersMiddleware
{
    readonly IEnumerable<string> _headersToRemove;
    readonly RequestDelegate _next;
    readonly ILoggerFactory _loggerFactory;
    /// <summary>
    /// Create an instance of <see cref="RemoveResponseHeadersMiddleware"/>
    /// </summary>
    /// <param name="next">the next <see cref="RequestDelegate"/> to call in the pipeline</param>
    /// <param name="optionsAccessor">the accessor to <see cref="CommaSeparatedListOptions"/> where headers to remove are configured</param>
    /// <param name="loggerFactory">the logger factory to create logger</param>
    public RemoveResponseHeadersMiddleware(RequestDelegate next, IOptions<CommaSeparatedListOptions> optionsAccessor, ILoggerFactory loggerFactory)
    {
        if (next == null)
            throw new ArgumentNullException("next");
        if (optionsAccessor == null || optionsAccessor.Options == null || optionsAccessor.Options.List == null)
            throw new ArgumentNullException("optionsAccessor");
        if (loggerFactory == null)
            throw new ArgumentNullException("loggerFactory");

        _next = next;
        _headersToRemove = optionsAccessor.Options.List;
        _loggerFactory = loggerFactory;
    }

    public async Task Invoke(HttpContext context)
    {
        await _next.Invoke(new RemoveHeaderHttpContext(context, _headersToRemove, _loggerFactory));            
    }
}

在调用方法中,我创建一个 httpcontext 装饰器并覆盖 httpresponse

public class RemoveHeaderHttpContext : HttpContext
{
    readonly HttpContext _parent;
    readonly HttpResponse _response;
    /// <summary>
    /// Create instance of <see cref="RemoveHeaderHttpContext"/>
    /// </summary>
    /// <param name="parent">the <see cref="HttpContext"/> to decorate/></param>
    /// <param name="headersToRemove">a list of unwanted header</param>
    /// <param name="loggerFactory">the logger factory to create logger</param>
    public RemoveHeaderHttpContext(HttpContext parent, IEnumerable<string> headersToRemove, ILoggerFactory loggerFactory)
    {
        if (parent == null)
            throw new ArgumentNullException("parent");
        if (headersToRemove == null)
            throw new ArgumentNullException("headersToRemove");
        if (loggerFactory == null)
            throw new ArgumentNullException("loggerFactory");

        _parent = parent;
        _response = new RemoveHeaderHttpResponse(this, parent.Response, headersToRemove, loggerFactory);
    }

    public override HttpResponse Response
    {
        get
        {
            return _response;
        }
    }

这个 httpresponse 是一个 httpresponse 的装饰器,它会覆盖 headers 集合

public class RemoveHeaderHttpResponse : HttpResponse
{
    readonly HttpResponse _parent;
    readonly HttpContext _context;
    readonly IHeaderDictionary _headers;
    /// <summary>
    /// Create instance of <see cref="RemoveHeaderHttpResponse"/>
    /// </summary>
    /// <param name="context">the <see cref="HttpContext"/> associated to the HTTP respone</param>
    /// <param name="parent">the <see cref="HttpResponse"/> to decorate</param>
    /// <param name="headersToRemove">a list of unwanted header</param>
    /// <param name="loggerFactory">the logger factory to create logger</param>
    public RemoveHeaderHttpResponse(HttpContext context, HttpResponse parent, IEnumerable<string> headersToRemove, ILoggerFactory loggerFactory)
    {
        if (parent == null)
            throw new ArgumentNullException("parent");
        if (headersToRemove == null)
            throw new ArgumentNullException("headersToRemove");
        if (loggerFactory == null)
            throw new ArgumentNullException("loggerFactory");

        _parent = parent;
        _context = context;
        _headers = new RemoveHeaderHeaderDictionary(parent.Headers, headersToRemove, loggerFactory);
    }

    public override IHeaderDictionary Headers
    {
        get
        {
            return _headers;
        }
    }

并且此 header 字典过滤管道中其他中间件添加的 header

public class RemoveHeaderHeaderDictionary : IHeaderDictionary
{
    readonly IHeaderDictionary _parent;
    readonly IEnumerable<string> _headersToRemove;
    /// <summary>
    /// Logger
    /// </summary>
    public ILogger Logger { get; private set; }
    /// <summary>
    /// Create an instance of <see cref="RemoveHeaderHeaderDictionary"/>
    /// </summary>
    /// <param name="parent">the <see cref="IHeaderDictionary"/> to decorate</param>
    /// <param name="headersToRemove">a list of unwanted header</param>
    /// <param name="loggerFactory">the logger factory to create logger</param>
    public RemoveHeaderHeaderDictionary(IHeaderDictionary parent, IEnumerable<string> headersToRemove, ILoggerFactory loggerFactory)
    {
        if (parent == null)
            throw new ArgumentNullException("parent");
        if (headersToRemove == null)
            throw new ArgumentNullException("headersToRemove");
        if (loggerFactory == null)
            throw new ArgumentNullException("loggerFactory");

        Logger = loggerFactory.Create<RemoveHeaderHeaderDictionary>();
        _parent = parent;
        _headersToRemove = headersToRemove;
        foreach (var header in headersToRemove)
            parent.Remove(header);
    }

    bool IsAllowedHeader(string header)
    {
        var allowed = !_headersToRemove.Any(h => h == header);
        Logger.WriteInformation(string.Format("{0} is {1}", header, allowed ? "allowed" : "not allowed"));
        return allowed;
    }

    public string this[string key]
    {
        get
        {
            return _parent[key];
        }

        set
        {
            if (IsAllowedHeader(key))
                _parent[key] = value;
        }
    }

但也许有更简单的方法?

You can find the whole code on github, project ChatLe.HttpUtility

关于c# - 如何删除每个响应上的一些 httpresponse header (例如 Server 和 ETag)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27637845/

相关文章:

c# - 即使更改 cshtml 文件,dotnet.exe 也会使用缓存

c# - 来自 textbox1 的用户输入 > 存储在列表中 > 在 textbox2 中输出

c# - Facebook C# SDK - 发布到墙上

c# - Expression.Lambda 有逆运算吗?

c# - Nerd Dinner 模型是否使用最佳实践来处理对象?

c# - 如何在缓存中存储数据?

c# - 运行 Windows 服务时拒绝访问

c# - 如何允许在 GridView 中排序

asp.net-mvc - 默认期限(20 分钟)后 MVC 5 session 超时

asp.net-mvc - 文本框电话号码格式 asp.net mvc