如何在服务器和ETag等每个响应中删除一些httpresponse标头?

时间:2014-12-24 13:41:47

标签: 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,但这并不适用于所有情况,特别是静态文件中间件

1 个答案:

答案 0 :(得分:1)

我所做的是一个覆盖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));            
    }
}

在invoke方法中,我创建了一个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女巫覆盖头集合

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;
        }
    }

这个标题字典过滤器标题由管道中的其他中间件添加

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