本文記錄一個 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
本文程式碼放在 github 和 gitee 上,可以使用如下命令列拉取程式碼。我整個程式碼倉庫比較龐大,使用以下命令列可以進行部分拉取,拉取速度比較快
先建立一個空資料夾,接著使用命令列 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 資料夾,即可獲取到原始碼
更多技術部落格,請參閱 部落格導航