福爆 | 博客升级 .NET Core 3.0 又踩一坑
點擊上方藍字關注“汪宇杰博客”
導語
昨天剛發了一篇《
生產大爆炸
發生問題的是已經被刪除的博客文章,正常情況下,這些不存在的文章會直接顯示自定義的404頁面,但實際上產生了500異常。日志如下:
2019-09-26?00:11:50.8405|RD00155DB89A5B|WARN|Moonglade.Web.Controllers.PostController|Post?not?found,?parameter?'2014/7/23/my-surface-pro-3-review-system-software'.,GET?https://edi.wang/post/2014/7/23/my-surface-pro-3-review-system-software,Slug,66.249.71.135
2019-09-26?00:11:51.1174|RD00155DB89A5B|WARN|Moonglade.Web.Controllers.PostController|Post?not?found,?parameter?'2014/7/23/my-surface-pro-3-review-system-software'.,GET?https://edi.wang/error,Slug,66.249.71.135
2019-09-26?00:11:51.1174|RD00155DB89A5B|ERROR|Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware|An?unhandled?exception?has?occurred?while?executing?the?request.,System.ArgumentException:?An?item?with?the?same?key?has?already?been?added.?Key:?x-pingback
???at?System.Collections.Generic.Dictionary`2.TryInsert(TKey?key,?TValue?value,?InsertionBehavior?behavior)
???at?System.Collections.Generic.Dictionary`2.Add(TKey?key,?TValue?value)
???at?Microsoft.AspNetCore.HttpSys.Internal.HeaderCollection.Add(String?key,?StringValues?value)
看上去像是個Pingback HTTP頭被重復添加的問題。但實際上這個頭被添加產生異常的本質原因是請求博客文章的Slug這個Action被執行了兩次。
重現故障
這個問題在開發時并沒有發現,staging環境可以重現,但由于偷懶,沒測過exception path,happy path過了就發布了。之所以開發環境 works on my machine 是因為這樣一個設定,大部分 ASP.NET Core 程序都會這么做,畢竟是默認模板里的實踐:
if (env.IsDevelopment())
{
? ? ListAllRegisteredServices(app);
? ? app.UseDeveloperExceptionPage();
}
else
{
? ? app.UseExceptionHandler("/error");
? ? app.UseStatusCodePagesWithReExecute("/error", "?statusCode={0}");
}
出問題的是?UseStatusCodePagesWithReExecute() 這個中間件。
最終在 GitHub 上找到了一個已知問題:
https://github.com/aspnet/AspNetCore/issues/13715
我用 VS2019 16.3.1 + .NET Core 3.0 正式版建了個測試工程,重現了這個問題。
public IActionResult Index(int id = 0)
{
? ? if (id == 1)
? ? {
? ? ? ? return NotFound();
? ? }
? ? return View();
}
[Route("/error")]
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error(int? statusCode = null)
{
? ? return Content($"Test Error Action: {statusCode}");
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
? ? //app.UseStatusCodePages();
? ? //app.UseExceptionHandler("/error");
? ? app.UseStatusCodePagesWithReExecute("/error", "?statusCode={0}");
? ? app.UseHttpsRedirection();
? ? app.UseStaticFiles();
? ? app.UseRouting();
? ? app.UseAuthorization();
? ? app.UseEndpoints(endpoints =>
? ? {
? ? ? ? endpoints.MapControllerRoute(
? ? ? ? ? ? name: "default",
? ? ? ? ? ? pattern: "{controller=Home}/{action=Index}/{id?}");
? ? });
}
訪問?/Home/Index?id=1
id=1的請求成功執行到 NotFound(); 正常情況應該立即執行 /error?statusCode=404,當實際上 Error 這個 Action 根本沒有跑進去,而是馬上再次執行了 Index,id=0
而因為執行的邏輯是ReExecute,也就是把action的執行結果放到“父”action里輸出,所以會觸發兩次pingback頭的添加,導致我博客大爆炸。
復制粘貼 能跑就行
微軟并不打算在 3.0 的補丁更新中修復這個問題,而是直接放到了 3.1。好在微軟提供了 workaround,所以我們只能先忍幾個月。
在 UseRouting() 和 UseStatusCodePagesWithReExecute() 之間加入一段神奇的代碼,即可結束福爆。
app.UseStatusCodePagesWithReExecute("/error", "?statusCode={0}");
// Workaround .NET Core 3.0 known bug
// https://github.com/aspnet/AspNetCore/issues/13715
app.Use((context, next) => {
? ? context.SetEndpoint(null);
? ? return next();
});
實在不行 刪庫跑路 也挺省心
目前 .NET Core 3.0 升級問題多多,資料少少,一不小心就容易領取福報。如果追求刺激和擁抱開源的樂趣,可以像我或者博客園一樣直接踩坑。如果追求穩定,不想被公司開除,建議等 3.1 再更新吧~ 畢竟微軟擁抱開源以后的產品,.1 才是能用的(早上更新的 VS2019 16.3.1笑而不語)。
總結
以上是生活随笔為你收集整理的福爆 | 博客升级 .NET Core 3.0 又踩一坑的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WinForms项目升级.Net Cor
- 下一篇: .NET Core使用NPOI导出复杂W