网站首页 网站源码
website
站点相关全部源代码,隐藏了一些关于服务器的信息
using System.Buffers;
using System.IO.Pipelines;
using Dpz.Core.Service.V4.Services;
using Wangkanai.Detection.Services;

namespace Dpz.Core.Web.Library.Middleware;

public class HttpRequestRecord(RequestDelegate next, IDiagnosticContext diagnosticContext)
{
    public async Task InvokeAsync(
        HttpContext httpContext,
        IArticleService articleService,
        IConfiguration configuration,
        IDetectionService detectionService
    )
    {
        if (httpContext.Request.Path.Equals("/sitemap.xml", StringComparison.OrdinalIgnoreCase))
        {
            var host = configuration.GetSection("upyun")["Host"] ?? "https://localhost:37701";
            var baseUri = new Uri(host);
            var uri = new Uri(baseUri, "/sitemap/sitemap.xml");
            httpContext.Response.Redirect(uri.ToString());
            return;
        }

        SetDetection(detectionService);
        await EnrichFromRequestAsync(httpContext.Request);

        await next.Invoke(httpContext);
        var routeValues = httpContext.Request.RouteValues;
        if (
            routeValues["controller"] is "Article"
            && routeValues["action"] is "Read"
            && routeValues["id"] is string id
        )
        {
            await articleService.ViewAsync(id);
        }
    }

    private async Task EnrichFromRequestAsync(HttpRequest request)
    {
        if (request.Query is { Count: > 0 })
        {
            diagnosticContext.Set("QueryString", request.Query);
        }

        var bodyContent = await GetBodyContentAsync(request.BodyReader);
        if (bodyContent != string.Empty)
        {
            diagnosticContext.Set("RequestBody", bodyContent);
        }
    }

    /// <summary>
    /// 读取 http body
    /// 如果 body 超过 1 &lt;&lt; 10 字节,则不记录 body
    /// </summary>
    /// <param name="reader"></param>
    /// <returns></returns>
    private static async Task<string> GetBodyContentAsync(PipeReader reader)
    {
        var result = new StringBuilder();
        const long maxLength = 1 << 10;
        long totalLength = 0;

        while (true)
        {
            var readResult = await reader.ReadAsync();
            var buffer = readResult.Buffer;
            // 如果 buffer 长度已经大于等于 maxLength,直接截取并返回
            if (buffer.Length >= maxLength)
            {
                var span = buffer.Slice(0, maxLength);
                AppendString(result, span);
                result.Append("...");
                reader.AdvanceTo(buffer.Start, buffer.GetPosition(maxLength));
                //await reader.CompleteAsync();
                break;
            }

            totalLength += buffer.Length;

            if (readResult.IsCompleted && buffer.Length > 0)
            {
                AppendString(result, in buffer);
            }

            reader.AdvanceTo(buffer.Start, buffer.End);
            if (totalLength >= maxLength)
            {
                result.Append("...");
                break;
            }

            if (readResult.IsCompleted)
            {
                break;
            }
        }

        return result.ToString();
    }

    private static void AppendString(
        StringBuilder result,
        in ReadOnlySequence<byte> readOnlySequence
    )
    {
        var span = readOnlySequence.IsSingleSegment
            ? readOnlySequence.First.Span
            : readOnlySequence.ToArray().AsSpan();
        result.Append(Encoding.UTF8.GetString(span));
    }

    private void SetDetection(IDetectionService detectionService)
    {
        diagnosticContext.Set("Device", detectionService.Device.Type.ToString());
        diagnosticContext.Set("Browser", detectionService.Browser.Name.ToString());
        diagnosticContext.Set("BrowserVersion", detectionService.Browser.Version.ToString());
        diagnosticContext.Set("Platform", detectionService.Platform.Name.ToString());
        diagnosticContext.Set("Engine", detectionService.Engine.Name.ToString());
        diagnosticContext.Set("Crawler", detectionService.Crawler.Name.ToString());
        diagnosticContext.Set("UserAgent", detectionService.UserAgent.ToString());
    }
}
⚠⚠    以下内容为AI分析的结果,请根据实际情况进行判断。

这段代码定义了一个中间件 HttpRequestRecord,用于处理 HTTP 请求并记录相关信息。它主要的功能包括:

  1. 重定向特定请求

    • 当请求的路径为 /sitemap.xml 时,代码会从配置中获取一个主机地址(默认为 https://localhost:37701),然后构建一个新的 URI,重定向到 /sitemap/sitemap.xml
  2. 设备和浏览器检测

    • 使用 IDetectionService 来检测请求的设备类型、浏览器名称、浏览器版本、平台名称、引擎名称、爬虫名称和用户代理,并将这些信息存储在 diagnosticContext 中。
  3. 请求信息的丰富

    • 通过 EnrichFromRequestAsync 方法,记录请求的查询字符串和请求体(body)。如果查询字符串不为空,则将其存储在 diagnosticContext 中。
    • 请求体的内容通过 GetBodyContentAsync 方法读取,最多读取 1024 字节(1 << 10),如果请求体超过这个长度,则只记录前 1024 字节并在后面加上省略号。
  4. 记录文章阅读

    • 在调用下一个中间件之前,检查请求的路由值。如果请求的控制器是 Article,动作是 Read,并且有一个有效的 id,则调用 articleService.ViewAsync(id) 方法记录文章的阅读。
  5. 读取 HTTP 请求体

    • GetBodyContentAsync 方法使用 PipeReader 读取请求体的内容。它会循环读取数据,直到达到最大长度或读取完成。读取的数据会被转换为字符串并返回。
  6. 字符串追加

    • AppendString 方法将读取的字节序列转换为字符串并追加到 StringBuilder 中。

总结

这个中间件的主要目的是在处理 HTTP 请求时,记录请求的相关信息(如查询字符串、请求体、设备和浏览器信息),并在特定条件下执行重定向和记录文章的阅读情况。这对于调试、分析和监控应用程序的请求非常有用。

loading