惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
小众软件
小众软件
MongoDB | Blog
MongoDB | Blog
Hugging Face - Blog
Hugging Face - Blog
Jina AI
Jina AI
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Stack Overflow Blog
Stack Overflow Blog
L
LangChain Blog
大猫的无限游戏
大猫的无限游戏
量子位
A
About on SuperTechFans
G
Google Developers Blog
雷峰网
雷峰网
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
IT之家
IT之家
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园_首页
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Vercel News
Vercel News
V
Visual Studio Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 聂微东
U
Unit 42
Apple Machine Learning Research
Apple Machine Learning Research

博客园 - Hey,Coder!

微信小程序 web方案实现调音器功能 systemctl slice配置docker最大占用cpu 内存 pipenv环境变量配置 .net8验证码 数据库差异对比工具 docker部署prometheus grafana pgexporter Alertmanager ubuntu24 换源 ssh配置 ubuntu24 Harbor部署 ubuntu24 kvm部署 cockpit web管理界面 Ubuntu 24.04 DMAR IOMMU 报错修复 uniapp iOS App 上架 vs文件软链接 Docker 网络别名 .net8通用中间件处理公共返回值结构 .net环境下OpenTelemetry Body 读取注意事项 jaeger界面显示异常 .net opentelemetry collector jaeger c# opentelemetry 自定义export c# opentelemetry 自定义export c# 生成对象的初始化代码 Elasticsearch ILM 与 Data Stream 概念及实例说明文档 portainer httphelper封装 Ocelot + Consul + SignalR 粘性会话 正交软件架构 docker postgresql17 主从复制 rabbitmq总结与c#示例 docker rabbitmq quartz dashboard docker consul registrator 服务自动注册consul 微服务动态扩容
.net api代理
Hey,Coder! · 2026-08-17 · via 博客园 - Hey,Coder!

背景

存在数量较多需要中转调用的接口,不可能每个接口都定义实体然后转发,可以直接编写通用的代理服务。

特殊逻辑

如果存在需要移除的url参数可以使用RemoveParamFromQueryString移除,本文需要移除参数中的__EnvID,根据实际情况调整。

调用方法

继承AgentBaseController 后创建接口

     /// <summary>
     /// 无代码系统列表(系统下拉)
     /// </summary>
     [HttpGet]
     [ApiIgnore]
     public IActionResult GetSystemList([FromQuery] EnvAgentDto dto)
     {
         var envBaseUrl="http://127.0.0.1:7000";

         var result = GetProxy("/api/NC/System/GetList", envBaseUrl);
         return result;
     }

     /// <summary>
     /// 
     /// </summary>
     [HttpPost]
     [ApiIgnore]
     public IActionResult GetTranslateValueInfo([FromQuery] EnvAgentDto dto)
     {
         var envBaseUrl="http://127.0.0.1:7000";

         var result = PostProxy("/api/common/TranslateValue/GetTranslateValueInfo", envBaseUrl);
         return result;
     }

     /// <summary>
     /// 
     /// </summary>
     [HttpPost]
     [ApiIgnore]
     public IActionResult GetPageList([FromQuery] EnvAgentDto dto)
     {
         var env = sysEnvService.GetByID(dto.__EnvID);
         ExceptionHelper.CheckNull(env, "EnvNull");
         callerAgent.IsAlive(env.EnvCode);

         var result = PostProxy("/api/NC/Page/GetList", env.EnvCfgAddress);
         return result;
     }

代理逻辑

 public class AgentBaseController : ServerBaseController
{
    private readonly string ContentType = "application/json; charset=utf-8";
    //private readonly string ContextType ="application/json";

    private readonly IHttpClientFactory _httpClientFactory;

    public AgentBaseController(IHttpClientFactory httpClientFactory)
    {
        _httpClientFactory = httpClientFactory;
    }

    protected IActionResult GetProxy(string path, string baseUrl)
    {
        if (string.IsNullOrWhiteSpace(baseUrl))
            return BadRequest(new { error = "Missing 'baseUrl' query parameter." });

        var filteredQuery = RemoveParamFromQueryString(Request.QueryString, "__EnvID");
        var targetUrl = $"{baseUrl.TrimEnd('/')}{path}{filteredQuery}";

        var client = _httpClientFactory.CreateClient();
        var requestMessage = new HttpRequestMessage(HttpMethod.Get, targetUrl);
        CopyHeaders(requestMessage);

        var response = client.SendAsync(requestMessage).Result;
        var content = response.Content.ReadAsStringAsync().Result;

        // 返回 JSON 格式,透传下游状态码
        return new ContentResult
        {
            Content = content,
            ContentType = ContentType,
            StatusCode = (int)response.StatusCode
        };
    }

    protected IActionResult PostProxy(string path, string baseUrl)
    {
        if (string.IsNullOrWhiteSpace(baseUrl))
            return BadRequest(new { error = "Missing 'baseUrl' query parameter." });

        Request.EnableBuffering();
        string bodyContent;
        using (var reader = new StreamReader(Request.Body, Encoding.UTF8, leaveOpen: true))
        {
            bodyContent = reader.ReadToEndAsync().Result;
            Request.Body.Position = 0;
        }

        var filteredQuery = RemoveParamFromQueryString(Request.QueryString, "__EnvID");
        var targetUrl = $"{baseUrl.TrimEnd('/')}{path}{filteredQuery}";

        var client = _httpClientFactory.CreateClient();
        var requestMessage = new HttpRequestMessage(HttpMethod.Post, targetUrl);
        CopyHeaders(requestMessage);
        requestMessage.Content = new StringContent(bodyContent, Encoding.UTF8, Request.ContentType ?? ContentType);

        var response = client.SendAsync(requestMessage).Result;
        var content = response.Content.ReadAsStringAsync().Result;

        return new ContentResult
        {
            Content = content,
            ContentType = ContentType,
            StatusCode = (int)response.StatusCode
        };
    }

    private static string RemoveParamFromQueryString(QueryString queryString, string paramName)
    {
        if (!queryString.HasValue)
            return string.Empty;

        var query = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(queryString.Value);
        query.Remove(paramName);

        var pairs = query.SelectMany(kv => kv.Value, (kv, v) => $"{kv.Key}={Uri.EscapeDataString(v)}");
        return pairs.Any() ? "?" + string.Join("&", pairs) : string.Empty;
    }

    private void CopyHeaders(HttpRequestMessage requestMessage)
    {
        var excludedHeaders = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
        {
            "Host", "Content-Length", "Transfer-Encoding", "Connection",
            "Keep-Alive", "Upgrade", "Proxy-Authorization", "Proxy-Connection",
            "TE", "Trailer"
        };

        foreach (var header in Request.Headers)
        {
            var key = header.Key;
            if (excludedHeaders.Contains(key))
                continue;
            if (key.Equals("Content-Type", StringComparison.OrdinalIgnoreCase))
                continue;

            if (!requestMessage.Headers.TryAddWithoutValidation(key, header.Value.ToArray()))
            {
                // 忽略无法添加的头部
            }
        }
    }
}