覆盖 Owin 中间件中的响应正文

Overwrite Response Body in Owin Middleware

提问人:Dominick 提问时间:4/23/2019 更新时间:9/17/2019 访问量:3063

问:

我有一个正在使用的 Owin 中间件类。目的是在检测到 401、403 或 405 HTTP 状态代码时覆盖响应正文,并将正文替换为 JSON 对象。这是我到目前为止的方法:

public override async Task Invoke(IOwinContext context)
        {
            await Next.Invoke(context);

            if (context.Response.StatusCode == 401 || context.Response.StatusCode == 403 || context.Response.StatusCode == 405)
            {

                var owinResponse = context.Response;
                var owinResponseStream = owinResponse.Body;
                var responseBuffer = new MemoryStream();
                owinResponse.Body = responseBuffer;

                string message;

                switch (context.Response.StatusCode)
                {
                    case 401:
                        message = "unauthorized request";
                        break;
                    case 403:
                        message = "forbidden request";
                        break;
                    default:
                        message = "request not allowed";
                        break;
                }
                var newResponse = new ResponseMessage<string>
                {
                    IsError = true,
                    StatusCode = (HttpStatusCode) Enum.Parse(typeof(HttpStatusCode), context.Response.StatusCode.ToString()),
                    Data = null,
                    Message = message
                };

                var customResponseBody = new StringContent(JsonConvert.SerializeObject(newResponse));
                var customResponseStream = await customResponseBody.ReadAsStreamAsync();
                await customResponseStream.CopyToAsync(owinResponseStream);
                owinResponse.ContentType = "application/json";
                owinResponse.ContentLength = customResponseStream.Length;
                owinResponse.StatusCode = 200;
                owinResponse.Body = owinResponseStream;
            }

        }

在大多数情况下,它正在工作,但是响应正文被追加到而不是替换。例如,在 401 错误的情况下,响应正文为:

{"message":"Authorization has been denied for this request."}
{"IsError":true,"StatusCode":401,"Data":null,"Message":"unauthorized request"}

而不是:

{"IsError":true,"StatusCode":401,"Data":null,"Message":"unauthorized request"}

我确信这与我写给响应机构的方式有关,但到目前为止还没有解决问题。

任何建议将不胜感激。

谢谢

C# ASP.NET-WEB-API 欠文

评论


答:

1赞 M. Abouzeid 4/23/2019 #1

当您第一次将响应正文设置为内存流时,光标(当前位置)将移动到它的末尾。 ,结果,我们被存储了,光标指向最后。owinResponse.Body = responseBuffer;{"message":"Authorization has been denied for this request."}

同样,在方法的末尾,您编写包含消息的新响应owinResponse.Body = owinResponseStream;{"IsError":true,"StatusCode":401,"Data":null,"Message":"unauthorized request"}

由于当前位置指向流的末尾,因此它将附加。

尝试删除第一组正文 owinResponse.Body = responseBuffer; 因为您不需要原始响应消息。

3赞 Chingiz Humbatov 9/17/2019 #2

因为你在下面写代码await Next.Invoke(context);

await Next.Invoke(context);

            if (context.Response.StatusCode == 401 || context.Response.StatusCode == 403 || context.Response.StatusCode == 405)
            {

                var owinResponse = context.Response;
                var owinResponseStream = owinResponse.Body;
                var responseBuffer = new MemoryStream();
                owinResponse.Body = responseBuffer;

这是错误的。

下一个代码可以根据需要工作:

public override async Task Invoke(IOwinContext context)
        {
            var owinResponse = context.Response;
            var owinResponseStream = owinResponse.Body;
            var responseBuffer = new MemoryStream();
            owinResponse.Body = responseBuffer;

            await Next.Invoke(context);

            if (context.Response.StatusCode == 401 || context.Response.StatusCode == 403 || context.Response.StatusCode == 405)
            {

                string message;

                switch (context.Response.StatusCode)
                {
                    case 401:
                        message = "unauthorized request";
                        break;
                    case 403:
                        message = "forbidden request";
                        break;
                    default:
                        message = "request not allowed";
                        break;
                }
                var newResponse = new ResponseMessage<string>
                {
                    IsError = true,
                    StatusCode = (HttpStatusCode) Enum.Parse(typeof(HttpStatusCode), context.Response.StatusCode.ToString()),
                    Data = null,
                    Message = message
                };

                var customResponseBody = new StringContent(JsonConvert.SerializeObject(newResponse));
                var customResponseStream = await customResponseBody.ReadAsStreamAsync();
                await customResponseStream.CopyToAsync(owinResponseStream);
                owinResponse.ContentType = "application/json";
                owinResponse.ContentLength = customResponseStream.Length;
                owinResponse.StatusCode = 200;
                owinResponse.Body = owinResponseStream;
            }

        }