# WebApi ###### tags: `Learning` ## 建立 ApiController  ## 預設改為 Json 格式回應 在 Global.asax 中加入一行: ``` // 關閉 XML 格式回應,就會預設回應 Json 格式 GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear(); ``` [參考資料](https://blog.miniasp.com/post/2012/10/12/ASPNET-Web-API-Force-return-JSON-format-instead-of-XML-for-Google-Chrome-Firefox-Safari) --- ## Json 序列化時 Exception JsonSerializationException Self referencing loop detected with type  ### 發生原因: Entity Framework...會建一些關聯的欄位... 這次的原因是 Employees 中,又有 Employees 的欄位,所以造成序列化無限迴圈 參考循環、循環參考... 這邊使用的是北風資料庫的 Employees Table,因為欄位中有一個 ReportsTo,就是員工要回報給誰(主管),所以那個 Employees2 是主管的資料。 至於 Employess1 呢? 為什麼是個清單,是指要回報狀況給此員工的員工是誰 Ex. A、B、C 都要回報給 D(主管),D 的 Employees1 就會有 A、B、C 的資料   ### 解法: ``` // 如果 Json 序列化是使用 Json.Net 序列化 ( 應該是微軟原生的Json(?) ), // 這行程式可以忽略循環引用 ( 就是 Model 中有相同類型的 Property,導致進行 Json 序列化時無限迴圈 ) config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; ``` ### 附註 #### JsonSerializerSettings > ReferenceLoopHandling.Error(默認)如果遇到參考循環將出錯。這就是為什麼您會獲得例外。 > ReferenceLoopHandling.Serialize 如果對像是嵌套的但不是無限期的,則很有用。 > ReferenceLoopHandling.Ignore 如果對象本身是子對象,則不會序列化該對象。 > > 原文↓ > > ReferenceLoopHandling.Error (default) will error if a reference loop is encountered. This is why you get an exception. ReferenceLoopHandling.Serialize is useful if objects are nested but not indefinitely. ReferenceLoopHandling.Ignore will not serialize an object if it is a child object of itself. [資料來源](https://stackoverflow.com/questions/7397207/json-net-error-self-referencing-loop-detected-for-type) --- ## Route 使用情境: 更新 API 的方法的時候,可用 v1、v2... 來做區別,為了相容舊系統 ( 還有系統用 v1,v1 就不能下線,所以此時 v1、v2 是同時在線上可以呼叫 ) 本來可能呼叫方法是 api/Employee 就能 Get 資料,但為了區分版本, 需要寫成 api/Employee/v1,這時候需要 Route,當然可以在 RouteConfig 專門設一個有版本的 Route 匹配。 但是如果只是偶發的版本情況,其實也可以直接在 Function 上加入 Route Attribute,直接指定路徑 <span style="color:red">特別注意!!WebApiConfig.cs 需要加上 config.MapHttpAttributeRoutes(); 才會參考 Attribute 的路由 </span>  ``` [Route("api/Employee/v1")] ``` FYI,路徑是可以加上一些驗證的喔 ``` [Route("api/Employee/v1/{id:regex}")] ``` ## Function 自定義改名 加上 HttpGet Attribute 就好  HttpGet 的優先權會高於 ``` public List<Employees> Get(){ //... } ``` --- ## CORS 跨來源資源共用 練習過程中直接遇到這個問題 > has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. #### 解法 1. 在專案中加入 Microsoft.AspNet.WebApi.Cors 的 Nuget 套件 2. 安裝完成後,打開專案中的[App_Start\WebApiConfig.cs]檔案,並在裡面加上一行"config.EnableCors();" 3. 在 Action 中加上 Attributeorigins代表允許存取的來源網域,headers代表允許的標頭,而method則是代表允許使用的方法,如Get或是Post等等,這幾個屬性的設定,若是更改為*,就代表允許所有的來源以及所有請求方式 [讓WebAPI可以跨網域執行,並動態指定允許呼叫的來源網域](https://dotblogs.com.tw/maduka/2018/01/29/214811) [Microsoft - 在 ASP.NET Web API 2 中啟用跨原始來源要求](https://docs.microsoft.com/zh-tw/aspnet/web-api/overview/security/enabling-cross-origin-requests-in-web-api) #### CORS的作用 ##### 為了改善網絡應用程式,開發人員要求瀏覽器供應商允許跨域請求。跨域請求主要用於: 1. 調用XMLHttpRequest或fetchAPI通過跨站點方式訪問資源 2. 網絡字體,例如Bootstrap(通過CSS使用@font-face 跨域調用字體) 3. 通過canvas標籤,繪製圖表和視頻。 #### CORS的安全隱患 1. HTTP頭只能說明請求來自一個特定的域:不能保證這個事實。因為HTTP頭可以被偽造。 2. 第三方有可能被入侵:像是 假設 Facebook 授權某個 Api 給 A 網站使用,而 A 網站被駭,則駭客可以使用該 Api 3. 惡意跨域請求:即便頁面只允許來自某個信任網站的請求,但是它也會收到大量來自其他域的跨域請求。.這些請求有時可能會被用於執行應用層面的DDOS攻擊,並不應該被應用來處理。 4. 內部資訊洩漏:假定一個內部站點開啟了CORS,如果內部網絡的用戶訪問了惡意網站,惡意網站可以通過COR(跨域請求)來獲取到內部站點的內容。 5. 針對用戶的攻擊:攻擊者並不是直接從它們的系統資料庫中獲取數據,他們可能會編寫一個JavaScript數據採集腳本,並在自己的網站或者存在XSS問題的網站上插入這段腳本。當受害者訪問含有這種惡意JavaScript腳本網站時,瀏覽器將執行針對「productsearch.php」的SQL注入攻擊,採集所有的數據並發送給攻擊者。檢查伺服器日誌顯示是受害人執行了攻擊,因為除了來自Referrer的HTTP頭一般沒有其他日誌記錄。受害者並不能說他的系統被攻破,因為沒有任何任何惡意軟體或系統泄漏的痕跡。 [CORS攻擊:跨源資源共享安全分析](https://kknews.cc/zh-tw/tech/e8apaan.html) #### 幾個重點 * 可以接受簡單的請求 ( 之前使用 WebService 都沒遇到這類問題,可能就是簡單請求 ),參考 -> [MDN - 跨來源資源共用(CORS)](https://developer.mozilla.org/zh-TW/docs/Web/HTTP/CORS) * 可以配合身分驗證 * 還是有風險 ---
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up