如何使用 WinInet API 以程式設計方式在 Internet Information Services 7.0 上使用 WebDav 上傳檔案

徵狀

請試想下列案例:

您的應用程式會透過使用 WinInet API 傳送 HTTP PUT 動詞,以程式設計方式將檔案上傳到由 IIS 7 託管的 WebDav 目錄。 您可能會遇到您的應用程式在 IIS6 和 Windows Server 2003 上正常運作,可能無法將檔案上傳到 IIS 7 WebDav 目錄,即使您的 WinInet 應用程式未變更任何程式碼也一樣。

原因

發生這個問題的原因是,在 IIS 7 上執行 WebDav 的設計變更。  在 IIS 7 上執行的 WebDav 現在需要驗證,如果只使用匿名驗證,就無法運作。 如此一來,您的應用程式在使用 WinInet API 序列 HttpSendRequestEx、InternetWriteFile、HttpEndRequest 時,將會出現 HttpEndRequest 傳回 FALSE 和 GetLastError ()的呼叫,以指示 12032-ERROR_INTERNET_FORCE_RETRY 的錯誤碼。

解決方案

這個問題的解決方式是重試相同的運算順序,亦即:

A.) HttpSendRequestExB.) InternetWriteFileC.) HttpEndRequest

直到 HttpEndRequest 沒有傳回 FALSE 且 GetLastError ()無法傳回12032(或發生其他錯誤)。 如果 IIS 出現錯誤的驗證資訊,則 IIS 將持續針對每次重試傳回 HTTP 401 錯誤。因此,您需要追蹤 HttpEndRequest 函數傳回錯誤12032的次數,從而避免執行無限迴圈。

在 Windows NTLM 驗證的情況下,HttpEndRequest 將會傳回錯誤12032,最多可滿足3種 NTLM 握手的速度。 第一個12032錯誤會指出來自伺服器的 HTTP 401 錯誤回應,而第二個12032錯誤會指出來自伺服器的類型 2 NTLM 握手訊息,如果將有效驗證資訊傳遞至 IIS,使用者就會正確驗證,且上傳就會成功。

當您使用 retry 邏輯在迴圈中呼叫上述函數時,請注意,對 InternetWriteFile 的呼叫正在進行多次。 這表示對 InternetWriteFile 的呼叫會在網路上結束寫入資料,這會造成頻寬浪費。 若要避免發生這種情況,您可以傳送虛擬的 HTTP HEAD 要求給伺服器,這將會「對要求進行預驗證」,並在呼叫 InternetWriteFile 時,導致 HttpSendRequest 的後續呼叫不會傳送 HTTP 負載。 如果您熟悉網路監視器或 WinInet 記錄,您會看到傳送給伺服器的第一個 PUT 要求的內容長度為零,這可避免負載轉移,且在 NTLM 握手完成之前,將不會傳輸該負載。

WebDav 功能不需要您使用 Windows 驗證;您可以將 WebDav 伺服器設定為使用 SSL 上的基本驗證,以確保資料上傳的安全性。 設定基本驗證之後,您可以直接在待發要求中注入有效的 base-64 編碼的使用者密碼字串,這將會防止 IIS 傳回 HTTP 401 錯誤,因此 HttpEndRequest 不會傳回錯誤12032。 您可以呼叫 WinInet API,將基本驗證資訊新增至傳出要求:

HttpAddRequestHeaders (hRequest,"授權:基本 <<有效的 base-64 編碼的使用者名稱:密碼字串>> \r\n"、-1、HTTP_ADDREQ_FLAG_ADD);

在呼叫 HttpSendRequestEx 之前,請先執行此動作,直接在外寄 HTTP 要求中注入授權標頭。

下列程式碼範例示範如何使用 retry 邏輯處理來自 HttpEndRequest 的錯誤12032傳迴響應。 請注意,這個範例並未涵蓋上述所述的「前期驗證」要求。 若要進行前驗證,您需要執行的操作就是呼叫 HttpOpenRequest,並在撥打以下 HttpSendRequestEx 程式碼前,HttpSendRequest 使用 HTTP HEAD 動詞給目標伺服器。

程式碼範例: = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

BOOL UseHttpSendReqEx (HINTERNET hRequest,DWORD dwPostSize) {INTERNET_BUFFERS BufferIn;   DWORD dwBytesWritten;   int iChunkCtr;   BYTE pBuffer [1024];   BOOL bRet;

    BufferIn. dwStructSize = sizeof (INTERNET_BUFFERS);必須設定,否則您會收到錯誤 BufferIn。接下來 = Null;    BufferIn. lpcszHeader = Null;   BufferIn. dwHeadersLength = 0;   BufferIn. dwHeadersTotal = 0;

    BufferIn. lpvBuffer = Null;                   BufferIn. dwBufferLength = 0;   BufferIn. dwBufferTotal = dwPostSize;這是除了 dwStructSize BufferIn 以外,只使用的成員。 dwOffsetLow = 0;   BufferIn. dwOffsetHigh = 0;

    --------------------------------------------------------------------------------------------//下列變數將追蹤 HttpSendRequestEx 稱為//--------------------------------------------------------------------------------------------int iNumTrials = 0 的次數;   bool bRetVal = FALSE;

    --------------------------------------------------------------------------------------------//Retry goto 是在 HttpEndRequest 傳回錯誤12032時,重新嘗試該操作。    --------------------------------------------------------------------------------------------while (1) {if (!HttpSendRequestEx (hRequest,&BufferIn,Null,0,0)) {printf ("HttpSendRequestEx%d\n" 的錯誤,GetLastError ());           傳回 FALSE;       }

        FillMemory (pBuffer,1024,"d");使用資料填滿緩衝區

        bRet = TRUE;       for (iChunkCtr = 1; iChunkCtr<= (int) dwPostSize/1024 && bRet; iChunkCtr +) {dwBytesWritten = 0;           if (bRet = InternetWriteFile (hRequest,pBuffer,1024,&dwBytesWritten)) printf ("\r%d 位元組傳送時間",iChunkCtr * 1024);       } if (! bRet) {printf ("InternetWriteFile%lu\n 中的 \N",GetLastError ());           傳回 FALSE;       }

        if (!HttpEndRequest (hRequest,Null,0,0)) {int iLastError = GetLastError ();           printf ("HttpEndRequest% lu \n" 的錯誤,iLastError);

            從 HttpEndRequest///錯誤 12032 = ERROR_INTERNET_FORCE_RETRY 收到錯誤12032之後,請--------------------------------------------------------------------------------------------//使用下列邏輯來 [retry]。表示您只需要再次傳送要求:////HttpSendRequest、InternetWriteFile、HttpEndRequest,直到 HttpEndRequest 沒有傳回//返回錯誤12032為止。             由於 NTLM 是三向握手通訊協定,所以 HttpEndRequest 將會傳回//錯誤 12032 2 時間,並因此進行下列檢查。            如果傳回錯誤 12032 3 個以上的次數,就會發生其他錯誤。            --------------------------------------------------------------------------------------------if (iLastError = = 12032 && iNumTrials < 3) {iNumTrials + +;               持續  這將會重試 HttpSendRequestEx .。。                   傳回 FALSE;       } 傳回 TRUE;   }}

其他相關資訊

http://learn.iis.net/page.aspx/350/installing-and-configuring-webdav-on-iis-70/

http://msdn.microsoft.com/en-us/library/aa384318(VS.85).aspx

http://msdn.microsoft.com/en-us/library/aa384227(VS.85).aspx

http://www.microsoft.com/download/details.aspx?FamilyID=983b941d-06cb-4658-b7f6-3088333d062f&displaylang=en

http://support.microsoft.com/kb/884931

Need more help?

Expand your skills
Explore Training
Get new features first
Join Microsoft Insiders

Was this information helpful?

Thank you for your feedback!

Thank you for your feedback! It sounds like it might be helpful to connect you to one of our Office support agents.

×