2016年3月3日 星期四

[Asp .Net Mvc]http status 400 的JsonResult在正式機器無法取得回傳的Json資料

在之前介紹客制JsonResult的時候([iThome 第七屆鐵人賽 28] Javascript和Mvc溝通 - 概念篇[iThome 第七屆鐵人賽 29] Javascript和Mvc溝通 - 實作篇),其中一個原因是爲了讓回傳的資訊可以利用http裏面的狀態碼(status code)設定為400來表示Json結果是錯誤, 然後前端接到的時候可以直接透過在error事件的function來處理有出錯的邏輯。而不是要在success function裏面透過回傳的json物件來判斷是否有成功。

在實際使用的時候,開發都沒有什麽問題,但是在正式機器的時候出現bug,會導致沒有辦法取得回傳的Json物件內容

這篇將會介紹發生的原因和如何處理。

問題描述

在我實際使用上面,在開發階段,return JsonError(),的確會回傳並且狀態是400(因此前端會進入error的function),並且json物件也有回傳回來。

但是在正式機器並非如此。在正式機器,也一樣會回傳400(所以也會進入error的function),但是json物件沒有傳送回來

從下面兩張截圖可以看到,正式機器和測試機器所回傳的內容: 測試機器的Request - 可以看到json資料有回傳回來

測試機器的Request - 可以看到json資料有回傳回來正式機器的Request - 可以看到json資料沒有回來

正式機器的Request - 可以看到json資料沒有回來

問題原因

可以看到在正式機器,本來要回傳的json資料沒有回傳回來,只出現錯誤的請求。光這樣看,一時之間還看不出問題。

如果把錯誤的請求翻譯成英文其實就是 Bad Request。這個詞就熟悉多了,不就是http 錯誤碼400的描述文字。

這個時候我的直覺就是,會不會和Asp .Net的客制錯誤訊息頁(CustomError)有沒有關係?

解決辦法

最後查到一篇SO,的確可能是IIS的Custom Error介入導致,這個時候,其實解決方法就簡單了,就是想辦法不要讓IIS介入就好。

有兩種解決方法:

  1. 在Web.config設定
  2. 在程式裏面處理

在Web.config設定

只需要在Web.config裏面放入:

    ...
    
    ...
web.config的好處是全域都有效果,但是有可能只是部份想要有這個效果,這個時候程式面的設定方法就會比較好。

在程式裏面設定

只要在程式裏面有呼叫:

Response.TrySkipIisCustomErrors = true;
即可。

修正之前客制的JsonResult

知道了解決方法之後,我們就可以針對之前程式碼的部份,在回傳之前加入Response.TrySkipIisCustomErrors = true; 即可:

protected virtual void SerializeData(HttpResponseBase response)
{
    if (ErrorMessages.Any())
    {
        var originalData = Data;
        Data = new
        {
            Success = false,
            OriginalData = originalData,
            ErrorMessage = string.Join("\n", ErrorMessages),
            ErrorMessages = ErrorMessages.ToArray()
        };
 
        response.StatusCode = 400;
        response.TrySkipIisCustomErrors = true;
    }
 
    var settings = new JsonSerializerSettings
    {
        ContractResolver = new CamelCasePropertyNamesContractResolver(),
 
        Converters = new JsonConverter[]
        {
            new StringEnumConverter(), 
        }
    };
 
    response.Write(JsonConvert.SerializeObject(Data, settings));
}

結語

有時候寫code真的要特別小心,尤其是這種正式機器才會發生的問題。不過好在,只要能夠抓到關鍵字,直接google大部份都 可以找到結果。

沒有留言 :

張貼留言