WinHTTP 版本差異
一般而言,Microsoft Game Development Kit (GDK) 遊戲與 WinHTTP 互動的方式,與 Win32 應用程式與 WinHTTP 互動的方式相同。 開發 Microsoft Game Development Kit (GDK) 遊戲時,只能使用 WinHTTP 的扁平 C/C++ API。這表示 HTTP 功能必須建置在此 HTTP 用戶端 API 之上。將 WinHTTP 新增至您的 XBOX 主機專案
在主機上,您應在原始程式檔中#include <winhttp.h>。您必須連結 XGamePlatform.lib,而非直接連結 Winhttp.lib。只有 WINAPI_PARTITION_GAMES API 系列下的 API 能在 Microsoft Game Development Kit (GDK) 遊戲中運作。在 Windows PC 上,您應繼續連結 Winhttp.lib。
如需如何將 WinHTTP 整合到 Microsoft Game Development Kit (GDK) 遊戲中的範例,請參閱 SimpleWinHttp 範例。它為您自己的 WinHTTP 實作提供了穩固的起點,並包含 WinHttpManager 類別。它公開了簡單的非同步 API 介面。
網路初始化與 WinHTTP
在您的遊戲第一次呼叫 WinHttpOpen 之前,Microsoft Game Development Kit (GDK) 遊戲必須確保網路堆疊已初始化。如果在遊戲啟動過程中過早呼叫WinHttpOpen,WinHttpOpen 或後續的 WinHTTP 呼叫可能會以非決定性的方式失敗或當機。在網路宣告為已初始化之前,要求可能看似成功但實際上失敗,反之亦然。如需如何判斷網路堆疊何時初始化的詳細資料,請參閱網路初始化。
遊戲暫停/繼續與 WinHTTP
收到遊戲暫停通知時,遊戲應啟動關閉所有 WinHTTP 控制代碼的程序。WinHTTP 控制代碼清除是非同步的。因此,您應依照下列順序關閉控制代碼:先關閉所有要求控制代碼,接著關閉所有連線控制代碼,最後關閉所有工作階段控制代碼。WinHTTP 控制代碼清除採用非同步方式,是為了確保通知執行緒的安全性。雖然是非同步的,但 WinHTTP 控制代碼清除不會延遲任何時間,因此能輕鬆符合一秒的暫停延期逾時限制。 繼續時,遊戲應遵循上述「網路初始化與 WinHTTP」一節所述的相同程序,並等候網路回到就緒狀態,再繼續使用 WinHTTP。暫停和繼續事件之間可能已經過很長一段時間,因此網路需要再次穩定,WinHTTP API 才會再次具有決定性。記憶體和並行考量
並行 WinHTTP 要求的數目應一律保持在八個以下,以確保 WinHTTP 內的非同步狀態能正確運作並維持在其記憶體預算內。此限制適用於遊戲執行階段內的所有並行作業,包括來自 XBOX services API 和XCurl 的呼叫。
作為 WinSock 記憶體考量的延伸,您應確保接收資料時,一律有以 WinHttpReadData 擱置的緩衝區 (或正在等候 WinHttpQueryDataAvailable 呼叫的回呼),以便盡快將資料從核心模式記憶體集區傳輸到您的使用者模式處理程序,並將 HTTP 作業所耗用的核心記憶體量降到最低。
WinHttpQueryHeaders getter 函式需要暫時性記憶體配置。它會配置大小等於 lpdwBufferLength 參數的暫存緩衝區供內部使用 (並在函式傳回前釋放)。因此,您應使用 WINHTTP_NO_OUTPUT_BUFFER 雙重呼叫模式,將暫存緩衝區的大小降到最低,並限制同時對 WinHttpQueryHeaders 進行的並行呼叫數目,以避免可能導致系統不穩定的過度系統記憶體使用量。標頭的預設大小上限為 64 KB,由 WINHTTP_OPTION_MAX_RESPONSE_HEADER_SIZE WinHTTP 選項指定。
WinHttpOpen 考量
旗標
您必須將下表中的旗標傳遞至 WinHttpOpen。
結合
WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY、WINHTTP_NO_PROXY_NAME 和 WINHTTP_NO_PROXY_BYPASS,可讓 Microsoft Game Development Kit (GDK) 平台自動處理 Fiddler 等 Proxy 及其他特殊情況的網路環境。
WINHTTP_FLAG_SECURE_DEFAULTS 旗標是一個新旗標,旨在藉由設定建議的安全連線行為,協助 Microsoft Game Development Kit (GDK) 遊戲遵循安全性最佳做法。它可在 XBOX One 主機上使用,並將在未來的 Windows 作業系統更新中於 Windows PC 上提供。嘗試在現有的 Windows 作業系統版本上傳遞 WINHTTP_FLAG_SECURE_DEFAULTS 會導致無效參數失敗。此旗標有一個重大的副作用:它會強制 WinHTTP 進入非同步模式,因為此旗標隱含地包含 WINHTTP_FLAG_ASYNC 旗標。在不支援此旗標的 Windows PC 作業系統版本上,您應改為傳遞 WINHTTP_FLAG_ASYNC,以將 WinHTTP 實作其餘部分的差異降到最低。
WINHTTP_FLAG_SECURE_DEFAULTS 旗標需要將相符的 WINHTTP_FLAG_SECURE 旗標傳遞給 WinHttpOpenRequest,並會封鎖未加密的 HTTP 要求。在用於內部偵錯和測試的開發套件上,您可以建立 WinHTTP 工作階段控制代碼,並對 WinHttpOpen 指定 WINHTTP_FLAG_ASYNC 旗標。此旗標可讓您在開發期間不對 WinHttpOpenRequest 指定 WINHTTP_FLAG_SECURE 旗標,以發出未加密的 HTTP 要求。對於非偵錯流量,您仍應使用以 WINHTTP_FLAG_SECURE_DEFAULTS 開啟的工作階段控制代碼,以符合您的遊戲在 RETAIL 中看到的要求行為。WINHTTP_OPTION_SECURE_PROTOCOLS
使用WinHttpOpen 建立新的工作階段控制代碼後,您必須以 WINHTTP_OPTION_SECURE_PROTOCOLS 選項呼叫 WinHttpSetOption,並傳遞對應的 XNetworkingSecurityInformation::enabledHttpSecurityProtocolFlags,該值是針對此工作階段控制代碼將使用的相符 URL 呼叫 XNetworkingQuerySecurityInformationForUrlUtf16Async 所擷取。您也應將 XNetworkingSecurityInformation 結構儲存在您的內容物件上,以供稍後驗證 TLS/SSL 交握時使用。
快取工作階段控制代碼
透過WinHttpOpen 建立的 HTTP 工作階段控制代碼在記憶體方面成本很高,且會產生延遲第一個 HTTP 要求的大量啟動成本。我們建議您在遊戲內盡可能快取 HTTP 工作階段控制代碼,以避免這些成本。
不過,無法變更工作階段控制代碼上的 WINHTTP_OPTION_SECURE_PROTOCOLS 選項。您應保留將 XNetworkingSecurityInformation::enabledHttpSecurityProtocolFlags 值對應至 WinHTTP 工作階段控制代碼的快取,以確保每個不同的安全通訊協定旗標都有不同的工作階段控制代碼。
您的遊戲所維護的快取必須在收到暫停通知時清除,並應在繼續時 (等候網路完成初始化之後) 從頭重建。
WinHttpConnect 考量
與工作階段控制代碼不同,透過 WinHttpConnect 建立的連線控制代碼絕不應快取。應為每個新要求和/或重試嘗試建立新的控制代碼。WinHTTP 連線控制代碼雖然名為連線,但與基礎伺服器傳輸控制通訊協定 (TCP) 連線沒有任何關係。WinHTTP 會透過工作階段控制代碼管理基礎伺服器連線的存留期,並盡可能自動為新的連線控制代碼重複使用已開啟的伺服器連線。URL 標準化
WinHTTP 預期所有 URL 都已標準化為 a-z、A-Z 和 0-9 的 US-ASCII 字元。如需標準化的詳細資訊,請參閱 WinHTTP 中的統一資源定位器 (URL)。我們建議盡可能以標準化形式硬式編碼您的遊戲所使用的 URL。此形式可避免使用 WinHttpCrackUrl 和 WinHttpCreateUrl 函式動態標準化 URL 所產生的記憶體配置和效能問題。URL 分割
WinHTTP 需要將以 Null 結尾的主機名稱字串傳遞給WinHttpConnect,而路徑和物件則傳遞給 WinHttpOpenRequest。您的遊戲在某些地方必須傳遞完整 URL (即串連的主機名稱和路徑),而在其他地方只傳遞主機名稱或路徑。我們建議您在遊戲中硬式編碼這兩者,以避免需要使用 WinHttpCrackUrl 和 WinHttpCreateUrl 動態串連或分割 URL。
WinHttpOpenRequest 考量
與 WinHTTP 連線控制代碼類似,透過 WinHttpOpenRequest 函式建立的 WinHTTP 要求控制代碼絕不應快取。應為每個新要求和/或重試嘗試建立新的控制代碼。 作為安全性最佳做法,遊戲在呼叫WinHttpOpenRequest 函式時,應一律為 dwFlags 參數傳遞 WINHTTP_FLAG_SECURE 旗標。
擷取及套用 XBOX services 權杖
Microsoft Game Development Kit (GDK) 遊戲不會自動插入權杖。相反地,遊戲應使用 Microsoft Game Development Kit (GDK) XUser API 擷取 XBOX services 驗證權杖和簽章。遊戲取得使用者之後,應呼叫 XUserGetTokenAndSignatureUtf16Async,為每個個別要求擷取權杖和簽章字串。接著,應在呼叫WinHttpAddRequestHeadersEx、WinHttpSendRequest 或 WinHttpAddRequestHeaders 時,將這兩個字串作為標頭傳遞。
為了產生正確的簽章,XUserGetTokenAndSignatureUtf16Async 預期遊戲傳遞所有標頭和整個本文。對於具有大型本文的 POST 或 PUT,遊戲可以傳遞在 Partner Center 中設定的本文子集。如需詳細資訊,請參閱 Web 服務 (NDA 主題)。目前,XBOX 網路並未提供擷取此設定的機制。用戶端應硬式編碼這些值,或透過自訂的遊戲專屬端點擷取這些值。
XUserGetTokenAndSignatureUtf16Async 會在內部執行所有必要的快取,且應在每次 HTTP 嘗試 (包括重試) 時呼叫。如果遊戲對任何 HTTP 要求收到 401 Unauthorized HTTP 回應狀態碼,遊戲應重試要求,並強制重新整理 XBOX services 驗證權杖。若要重新整理,請使用 XUserGetTokenAndSignatureUtf16Async 擷取新權杖,並傳遞 XUserGetTokenAndSignatureOptions::ForceRefresh 列舉值。
遊戲取得透過呼叫 XUserGetTokenAndSignatureUtf16Async 擷取的 XUserGetTokenAndSignatureUtf16Data 之後,必須將 XUserGetTokenAndSignatureUtf16Data::Token 和 XUserGetTokenAndSignatureUtf16Data::Signature 轉換為要傳遞至 WinHTTP 的 HTTP 標頭。新增了新的 WinHTTP API WinHttpAddRequestHeadersEx,專門用來降低 Microsoft Game Development Kit (GDK) 遊戲的複雜度。下列範例示範如何使用這個新 API。此新 API 可在 XBOX One 主機上使用,並將在未來的 Windows 作業系統更新中於 Windows PC 上提供。在主機上,我們建議您使用 WinHttpAddRequestHeadersEx,以避免額外的配置和字串格式變更。
裝置或已登入的帳戶必須能夠存取其所設定的沙箱。否則,
XUserGetTokenAndSignatureUtf16Data 會失敗。使用 XBOX 網路安全性授權清單 (NSAL)
XBOX 網路使用 NSAL 確保用戶端與您的 Web 服務建立安全且經過驗證的連線。遊戲會在 Partner Center 中將 NSAL 的內容作為其設定的一部分進行管理。如需詳細資訊,請參閱在 Partner Center 設定 Web 服務 (NDA 主題)。接著會自動為每個遊戲下載 NSAL 設定。它既用於產生適當的 XBOX services 權杖,也用於對您遊戲的特定端點執行憑證關聯。}WinHTTP 非同步狀態機器考量
主機上的 WinHTTP 非同步狀態機器與 Windows PC 上的相同。若要向一或多個通知註冊回呼函式,請使用 WinHttpSetStatusCallback 函式。基於偵錯目的,我們建議對dwNotificationFlags 參數使用 WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS 旗標,因為 WinHTTP 對於其正在執行的動作相當詳細且透明。雖然大部分通知不需要您採取任何動作,但記錄資料有助於找出問題的根本原因。
WinHTTP 使用單一執行緒處理通知。遊戲應盡可能避免封鎖任何通知函式,因為這會讓處理程序內的所有 HTTP 要求都無法進行。未處理的通知也可能增加核心模式記憶體,進而導致當機。
WinHTTP 不會複製您的傳送或接收緩衝區,並要求您在對應的完成回呼之前保持這些緩衝區為已配置狀態。請確保從呼叫 WinHttpSendRequest 到收到對應的 WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE 通知為止,傳送緩衝區都保持已配置且有效。同樣地,每次呼叫 WinHttpReadData 時,請確保接收緩衝區在收到對應的 WINHTTP_CALLBACK_STATUS_READ_COMPLETE 通知之前都保持已配置且有效。我們也建議使用至少 8 KB 大小的接收緩衝區,以避免可能導致堆疊耗盡的遞迴問題。
遊戲也應持續進行非同步的 WinHttpQueryDataAvailable/WinHttpReadData 循環,並且不在任何時間封鎖 WinHTTP 回呼,以確保 WinHTTP 緩衝區正確清空。
驗證傳輸層安全性 (TLS)/安全通訊端層 (SSL) 交握
作為安全性最佳做法,遊戲應執行 TLS/SSL 交握驗證,且只使用 TLS 1.2。 額外的驗證會在WINHTTP_CALLBACK_STATUS_SENDING_REQUEST 通知內執行。在此通知內,您必須呼叫 XNetworkingVerifyServerCertificate 函式,並傳入先前對應呼叫 XNetworkingQuerySecurityInformationForUrlUtf16Async 所擷取的 XNetworkingSecurityInformation 結構。如果憑證鏈結無效,此函式會失敗。您應在回呼完成之前立即關閉 WinHTTP 控制代碼,以確保不會與遭入侵的伺服器之間傳輸任何資料。
除了驗證憑證鏈結之外,主機上的 Fiddler 功能也需要 XNetworkingVerifyServerCertificate 函式。
偵錯 WinHTTP
Fiddler 是檢視及偵錯 WinHTTP 流量的實用工具。若要讓 Fiddler 擷取您的遊戲流量,您必須將WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY、WINHTTP_NO_PROXY_NAME 和 WINHTTP_NO_PROXY_BYPASS 旗標傳遞給 WinHttpOpen。您也必須在 WINHTTP_CALLBACK_STATUS_SENDING_REQUEST 通知回呼內呼叫 XNetworkingVerifyServerCertificate。
HTTP Monitor 不適用於 Microsoft Game Development Kit (GDK) 遊戲。
