You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用nuget push命令向私有BaGetter服务器上传包时始终发送0字节内容的问题求助

nuget push命令向私有BaGetter服务器上传包时始终发送0字节内容的问题求助

我在使用以下两个NuGet推送命令时遇到了奇怪的问题:

nuget.exe push -Source <url> -ApiKey <key> <package-file>
dotnet nuget push -s <url> -k <key> <package-file>

我的源是一个私有BaGetter服务。这两个命令都失败了,因为它们发送到服务器的HTTP PUT请求只有以下标头,没有请求体:

Content-Length: 0
Content-Type: multipart/form-data; boundary="<random-guid>"

我通过在BaGetter前面临时加了一个仅记录标头和请求体的虚拟处理程序确认了这一点。

有意思的是,用Postman直接发送HTTP PUT请求完全正常,包能正确送达。此时的请求标头是这样的:

Content-Length: 1695506
Content-Type: application/octet-stream

我到底在使用原始NuGet推送命令时忽略了什么?补充一下:我的BaGetter服务器部署在Cloudflare隧道后面,没有直接暴露在公网。


更新:我尝试了以下操作,但都没有效果

  • 禁用该BaGetter服务域名在Cloudflare上的HSTS要求
  • 将TLS要求降到最低的1.0版本

按照@zivkan的建议,我甚至自己写了一个简单的C#控制台应用,用HttpClient实现推送,结果完全正常,和预期一样。但我还是搞不懂为什么nuget.exe和dotnet nuget push命令一直失败。

以下是我的完整应用代码:

using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;

namespace FauxNuGetClient
{
    public class Program
    {
        public static async Task<int> Main(string[] args)
        {
            if (args == null || args.Length == 0 || !String.Equals(args[0], "push", StringComparison.OrdinalIgnoreCase))
            {
                Console.Error.WriteLine("Invalid args. Only 'push' is supported.");
                return -1;
            }

            var pairs = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            string pendingKey = null;
            string package = null;

            for (var i = 1; i < args.Length; i++)
            {
                if (pendingKey != null)
                {
                    pairs[pendingKey] = args[i];
                    pendingKey = null;
                    continue;
                }

                switch (args[i].ToLowerInvariant())
                {
                    case "-source":
                    case "-apikey":
                    case "-verbosity":
                        {
                            pendingKey = args[i].TrimStart('-');
                            continue;
                        }
                }

                if (i == 1 || i == args.Length - 1)
                {
                    package = args[i];
                    continue;
                }

                Console.Error.WriteLine("Invalid args. The 'push' command only recognizes -Source, -ApiKey, and -Verbosity parameters.");
                return -2;
            }

            if (String.IsNullOrEmpty(package) || !pairs.TryGetValue("source", out var url) || !Uri.TryCreate(url, UriKind.Absolute, out var uri))
            {
                Console.Error.WriteLine("Invalid args. The 'push' command requires -Source parameter that contains a valid absolute URL.");
                return -3;
            }

            if (!File.Exists(package))
            {
                Console.Error.WriteLine("Invalid args. The 'push' command requires an existing local file name.");
                return -4;
            }

            try
            {
                var uploadUrl = uri.GetComponents(UriComponents.SchemeAndServer, UriFormat.Unescaped).TrimEnd('/') + "/api/v2/package/";
                if (!Uri.TryCreate(uploadUrl, UriKind.Absolute, out uri))
                {
                    Console.Error.WriteLine("Invalid args. Unable to reparse the URI.");
                    return -5;
                }

                using (var client = new HttpClient { BaseAddress = uri, Timeout = TimeSpan.FromSeconds(45) })
                {
                    Console.WriteLine("PUT " + uri.ToString());

                    using (var fileStream = new FileStream(package, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        var requestContent = new MultipartFormDataContent();
                        var packageContent = new StreamContent(fileStream);
                        packageContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/octet-stream");
                        requestContent.Add(packageContent, "package", "package.nupkg");

                        if (pairs.TryGetValue("apikey", out var apiKey) && !String.IsNullOrWhiteSpace(apiKey))
                        {
                            requestContent.Headers.Add("X-NuGet-ApiKey", apiKey.Trim());
                        }

                        using (var response = await client.PutAsync("", requestContent))
                        {
                            if (response.IsSuccessStatusCode)
                            {
                                Console.WriteLine("OK.");
                                return 0;
                            }

                            Console.WriteLine("Failed. Status code: " + response.StatusCode.ToString());
                            return -6;
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("Failed. Exception: " + e.Message);
                return -7;
            }
        }
    }
}

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 12:38:00