dotnet 預設建立的 JsonContent 沒有 Content Lenght 的內容頭

lindexi發表於2024-08-24

本文記錄一個 dotnet 的設計問題,預設建立出來的 JsonContent 物件的 Headers 裡,是沒有 Content-Length 資訊的

如下面程式碼建立一個 JsonContent 物件

using System.Net.Http.Json;

var foo = new Foo();

var jsonContent = JsonContent.Create(foo);

class Foo
{
    public int Value { set; get; }
}

此時如果遍歷 JsonContent 的 Headers 屬性,將只可以拿到 Content-Type 資訊,沒有 Content-Length 資訊

在現代的絕大部分服務端,都是支援 Content 不帶 Content-Length 資訊的,這在大部分後臺上都能正常符合預期工作

即使用大概如下程式碼的 JsonContent 傳送出去的請求,在請求裡面也是不帶 Content-Length 資訊的

    var foo = new Foo();
    var jsonContent = JsonContent.Create(foo);

    var httpClient = new HttpClient();
    await httpClient.PostAsync("https://blog.lindexi.com", jsonContent);

那如何可以讓 JsonContent 帶上 Content-Length 資訊?只需呼叫 LoadIntoBufferAsync 方法,如以下程式碼

var jsonContent = JsonContent.Create(foo);

await jsonContent.LoadIntoBufferAsync();

呼叫完成 LoadIntoBufferAsync 方法,即可在 Headers 裡面看到 Content-Length 資訊,且使用如下程式碼傳送請求也是帶上 Content-Length 資訊的

    await jsonContent.LoadIntoBufferAsync();

    var httpClient = new HttpClient();
    await httpClient.PostAsync("https://blog.lindexi.com", jsonContent);

我檢視請求的資訊是透過自己建立一個簡單的 ASP.NET Core 程式,程式碼大概如下

var builder = WebApplication.CreateSlimBuilder(args);

var app = builder.Build();

app.MapPost("/", async context =>
{
    await Task.CompletedTask;
    var headers = context.Request.Headers;
});

app.Run();

透過斷點在 var headers = context.Request.Headers; 即可瞭解客戶端請求傳送過來的請求頭資訊

以及將此請求嘗試傳送到其他伺服器上,透過抓包確定了具體的行為

這在 dotnet 裡面認為設計如此,且認為如果沒有足夠多的報告說缺少 Content-Length 資訊會讓後臺不工作,則依然保持此行為

討論內容請看:

.NET 6: JsonContent.Create(obj) should set Content-Length HTTP request header · Issue #70793 · dotnet/runtime

Content-Length not appended when using JsonContent · Issue #82984 · dotnet/runtime

Provide better json support for servers don't support chunked request body (re-open) · Issue #55583 · dotnet/runtime

本文程式碼放在 githubgitee 上,可以使用如下命令列拉取程式碼。我整個程式碼倉庫比較龐大,使用以下命令列可以進行部分拉取,拉取速度比較快

先建立一個空資料夾,接著使用命令列 cd 命令進入此空資料夾,在命令列裡面輸入以下程式碼,即可獲取到本文的程式碼

git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 1b312eb1bfb867e56c5bbc61df720819fe1e15fc

以上使用的是國內的 gitee 的源,如果 gitee 不能訪問,請替換為 github 的源。請在命令列繼續輸入以下程式碼,將 gitee 源換成 github 源進行拉取程式碼。如果依然拉取不到程式碼,可以發郵件向我要程式碼

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin 1b312eb1bfb867e56c5bbc61df720819fe1e15fc

獲取程式碼之後,進入 Workbench/CaiballkaylecaWairlaroweneno 資料夾,即可獲取到原始碼

更多技術部落格,請參閱 部落格導航

相關文章