簡體   English   中英

如何安全地攔截自定義Owin中間件中的響應流

[英]How can I safely intercept the Response stream in a custom Owin Middleware

我正在嘗試編寫一個簡單的OWIN中間件,以攔截響應流。 我要做的是用自定義的基於Stream的類替換原始流,在那里我將能夠攔截對響應流的寫入。

但是,我遇到了一些問題,因為我無法知道響應是否已被鏈中的內部中間件組件完全寫入。 永遠不會調用Stream的Dispose重寫。 所以我不知道什么時候進行我的處理,這應該發生在響應流的末尾。

這是一個示例代碼:

public sealed class CustomMiddleware: OwinMiddleware
{
    public CustomMiddleware(OwinMiddleware next)
        : base(next)
    {
    }

    public override async Task Invoke(IOwinContext context)
    {
        var request = context.Request;
        var response = context.Response;

        // capture response stream

        var vr = new MemoryStream();
        var responseStream = new ResponseStream(vr, response.Body);

        response.OnSendingHeaders(state =>
        {
            var resp = (state as IOwinContext).Response;
            var contentLength = resp.Headers.ContentLength;

            // contentLength == null for Chunked responses

        }, context);

        // invoke the next middleware in the pipeline

        await Next.Invoke(context);
    }
}

public sealed class ResponseStream : Stream
{
    private readonly Stream stream_; // MemoryStream
    private readonly Stream output_; // Owin response
    private long writtenBytes_ = 0L;

    public ResponseStream(Stream stream, Stream output)
    {
        stream_ = stream;
        output_ = output;
    }

    ... // System.IO.Stream implementation

    public override void Write(byte[] buffer, int offset, int count)
    {
        // capture writes to the response stream in our local stream
        stream_.Write(buffer, offset, count);

        // write to the real output stream
        output_.Write(buffer, offset, count);

        // update the number of bytes written

        writtenBytes_ += count;

        // how do we know the response is complete ?
        // we could check that the number of bytes written
        // is equal to the content length, but content length
        // is not available for Chunked responses.
    }

    protected override void Dispose(bool disposing)
    {
        // we could perform our processing
        // when the stream is disposed of.
        // however, this method is never called by
        // the OWIN/Katana infrastructure.
    }
}

正如我在上面代碼的評論中提到的那樣,我可以想到兩種策略來檢測響應是否完整。

a)我可以記錄寫入響應流的字節數,並將其與預期的響應長度相關聯。 但是,在使用Chunked Transfer Encoding的響應的情況下,長度是未知的。

b)在響應流上調用Dispose時,我可以決定響應流是否完整。 但是,OWIN / Katana基礎結構從不在已替換的流上調用Dispose。

我一直在研究Opaque Streaming ,以便了解操縱底層HTTP協議是否是一種可行的方法,但我似乎沒有發現Katana是否支持Opaque Streaming。

有沒有辦法實現我想要的?

我不認為你需要一個子類流,但接下來就是你如何閱讀響應。 確保這個中間件是OWIN管道中的第一個,這樣它就是最后一個檢查響應的中間件。

using AppFunc = Func<IDictionary<string, object>, Task>;

public class CustomMiddleware
{
    private readonly AppFunc next;

    public CustomMiddleware(AppFunc next)
    {
        this.next = next;
    }

    public async Task Invoke(IDictionary<string, object> env)
    {
        IOwinContext context = new OwinContext(env);

        // Buffer the response
        var stream = context.Response.Body;
        var buffer = new MemoryStream();
        context.Response.Body = buffer;

        await this.next(env);

        buffer.Seek(0, SeekOrigin.Begin);
        var reader = new StreamReader(buffer);
        string responseBody = await reader.ReadToEndAsync();

        // Now, you can access response body.
        Debug.WriteLine(responseBody);

        // You need to do this so that the response we buffered
        // is flushed out to the client application.
        buffer.Seek(0, SeekOrigin.Begin);
        await buffer.CopyToAsync(stream);
    }
}

據我所知,BTW源自OwinMiddleware並不是一個好習慣,因為OwinMiddleware是專門針對Katana的。 但是,它與你的問題無關。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM