无法通过.NET Core代理服务转发GitHub Webhook至Jenkins
问题描述
环境配置
- 内网部署Jenkins与Traefik;DMZ区域IIS上部署自行开发的.NET Core代理服务(可公开访问),用于接收GitHub Webhook并转发至内网Jenkins。
错误信息
System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception. ---> System.Security.Authentication.AuthenticationException: Authentication failed because the remote party sent a TLS alert: 'InternalError'. ---> System.ComponentModel.Win32Exception (0x80090326): The message received was unexpected or badly formatted. --- End of inner exception stack trace --- // 更多堆栈信息...
代理服务核心代码
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using System.Net.Http; using System.Text; using System.Threading.Tasks; namespace GithubProxy.Controllers { [Route("api/[controller]")] [ApiController] public class GitController : ControllerBase { private readonly HttpClient _httpClient; private readonly ILogger<GitController> _logger; public GitController(IHttpClientFactory httpClientFactory, ILogger<GitController> logger) { _logger = logger; _httpClient = httpClientFactory.CreateClient(); } [HttpPost("notifyCommit")] public async Task<IActionResult> GitHubWebhook([FromBody] dynamic payload) { return ToActionResult(await ForwardPayloadToJenkins(payload, HttpContext.Request.Headers)); } private async Task<HttpResponseMessage> ForwardPayloadToJenkins(dynamic payload, IHeaderDictionary headers) { string jsonPayload = payload.ToString(); string jenkinsUrl = "https://jenkins.xxx.xx/github-webhook/"; foreach (var header in headers) { _httpClient.DefaultRequestHeaders.TryAddWithoutValidation(header.Key, header.Value.ToString()); } HttpContent content = new StringContent(jsonPayload, Encoding.UTF8, "application/json"); return await _httpClient.PostAsync(jenkinsUrl, content); } public IActionResult ToActionResult(HttpResponseMessage response) { if (response.IsSuccessStatusCode) { return new OkResult(); } else { string errorMessage = response.Content.ReadAsStringAsync().Result; return new ObjectResult(errorMessage) { StatusCode = (int)response.StatusCode }; } } } }
预期结果
代理服务可成功将GitHub Webhook请求转发至内网Jenkins
解决方案
1. 修复TLS版本与证书验证问题
内网Traefik/Jenkins可能仅支持TLS 1.2+,而.NET Core HttpClient默认配置可能不匹配。修改HttpClient的TLS配置:
// 在ConfigureServices或构造函数中替换HttpClient初始化逻辑 var handler = new HttpClientHandler { SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls13, // 生产环境请勿直接跳过验证,需将内网CA根证书导入DMZ服务器信任列表 ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true }; _httpClient = new HttpClient(handler);
2. 过滤无效请求头
原代码转发所有请求头,部分头(如Host、Content-Length)会干扰目标服务器的TLS握手与请求解析,仅保留GitHub Webhook必需的头:
// 替换原头循环逻辑 var allowedHeaders = new HashSet<string> { "X-GitHub-Event", "X-Hub-Signature", "X-Hub-Signature-256", "User-Agent" }; foreach (var header in headers) { if (allowedHeaders.Contains(header.Key) && !_httpClient.DefaultRequestHeaders.Contains(header.Key)) { _httpClient.DefaultRequestHeaders.TryAddWithoutValidation(header.Key, header.Value.ToString()); } }
3. 修正Payload序列化方式
dynamic.ToString()可能导致JSON格式错误,改用专业序列化库保证格式一致性:
// 先安装Newtonsoft.Json包:Install-Package Newtonsoft.Json string jsonPayload = JsonConvert.SerializeObject(payload);
4. 验证网络与DNS连通性
- 确认DMZ服务器能正确解析
jenkins.xxx.xx到内网IP - 在DMZ服务器执行测试命令验证TLS握手:
Invoke-WebRequest -Uri "https://jenkins.xxx.xx/github-webhook/" -Method Post -ContentType "application/json" -Body "{}"
若测试同样报错,说明问题出在网络或Traefik的TLS配置,而非代码。
5. 检查Traefik TLS配置
- 确认Traefik使用的证书有效且未过期
- 禁用TLS 1.0/1.1等旧版本协议
- 确保加密套件配置符合.NET Core客户端支持范围
内容的提问来源于stack exchange,提问作者Gift Ntokozo Mavuso
相关产品推荐
相关产品推荐

