Windows中有一组WinINet函数(http://msdn.microsoft.com/en-us/library/aa385473(v=VS.85).aspx),其中关于向Internet发送/接受请求的函数比较奇怪,尤其是HttpSendRequest函数问题更是诡异,下面是代码示例(该代码只是分析出问题,但没找到原因)

这组测试代码假设网络都是正常的.
 
 
    
  1. BOOL SendHttpHeaderTest() 
  2.     BOOL bRet = FALSE; 
  3.     if (ERROR_SUCCESS != ::InternetAttemptConnect(0)) 
  4.         return FALSE; 
  5.  
  6.     if (!::InternetCheckConnection(_T("http://www.baidu.com"), FLAG_ICC_FORCE_CONNECTION, 0)) 
  7.         return FALSE; 
  8.  
  9.     TCHAR szModuleFile[MAX_PATH] = {0}; 
  10.     ::GetModuleFileName(::GetInstance(), szModuleFile, MAX_PATH); 
  11.     LPCTSTR lpPath = ::PathFindFileName(szModuleFile); 
  12.     HINTERNET hOpen = ::InternetOpen(lpPath, INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY, NULL, NULL, 0); 
  13.     DWORD dwErr = ::GetLastError();//返回0 
  14.  
  15.     HINTERNET hConnect = ::InternetConnect(hOpen, _T("www.baidu.com"), INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); 
  16.     dwErr = ::GetLastError();//返回0 
  17.  
  18. #if 1 
  19.     DWORD dwFlag = INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_NO_AUTO_REDIRECT | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_COOKIES; 
  20.     HINTERNET hOpenRequest = ::HttpOpenRequest(hConnect, _T("GET"), _T("img/baidu_sylogo1.gif"), _T("HTTP/1.1"), _T("http://www.baidu.com/"), NULL, dwFlag, 0); 
  21.     dwErr = ::GetLastError();//返回122 
  22.  
  23.  
  24.     bRet = ::HttpSendRequest(hOpenRequest, NULL, 0, NULL, 0); 
  25.     dwErr = ::GetLastError();//返回0 
  26. #endif 
  27.  
  28.     TCHAR szBuff[BUFF_LEN_1024] = {0}; 
  29.     DWORD dwBuffSize = BUFF_LEN_1024; 
  30.     bRet = ::HttpQueryInfo(hOpenRequest, HTTP_QUERY_STATUS_CODE, (LPVOID)szBuff, &dwBuffSize, NULL); 
  31.     dwErr = ::GetLastError();//返回0 
  32.  
  33.     //Reference to http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html 
  34.     int nStatusCode = _tstoi(szBuff);// 值为200,证明请求数据baidu_sylogo1.gif是成功的. 
  35.     if (nStatusCode<200 || 206
  36.         bRet = FALSE; 
  37.  
  38.     bRet = TRUE; 
  39.     ::InternetCloseHandle(hConnect); 
  40.  
  41.     ::InternetCloseHandle(hOpen); 
  42.  
  43.     return bRet; 
 
#if 1 ... #endif HttpOpenRequest说明要向www.baidu.com请求baidu_sylogo1.gif,但这个函数是不会向www.baidu.com发送任何数据的,只有调用HttpSendRequest时才会发送这个请求.
  HttpOpenRequest函数的返回值很有意思,可以看到它的返回值是有效的,证明对该函数的调用是成功的,但问题dwErr返回值是122,它的含义是 ERROR_INSUFFICIENT_BUFFER: The data area passed to a system call is too small,但不知道什么意思,也不知到如何才能使dwErr成为0.
  根据msdn中的描述,这段代码可以用下面一段代码替换:
 
 
    
  1. #if 2  
  2.     HINTERNET hOpenRequest = ::HttpOpenRequest(hConnect, NULL, NULL, NULL, NULL, NULL, dwFlag, 0);  
  3.     dwErr = ::GetLastError();//仍然返回122  
  4.   
  5.     LPCTSTR lpHeader =   
  6.     _T("GET /img/baidu_sylogo1.gif /HTTP/1.1")//A line  
  7.     _T("Referer: http://www.baidu.com/\r\n")  //B line  
  8.     _T("Host: www.baidu.com")                 //C line  
  9.     _T("\r\n\r\n");                           //D line  
  10.   
  11.     DWORD dwHeaderLen = _tcslen(lpHeader); 
  12.     bRet = ::HttpAddRequestHeaders(hOpenRequest, lpHeader, dwHeaderLen, HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE); 
  13.  
  14.     bRet = ::HttpSendRequest(hOpenRequest, NULL, 0, NULL, 0);  
  15.     dwErr = ::GetLastError();//返回0  
  16. #endif  
  17. // 注意观察lpHeaer的值,有如下几个特点:1)它的结尾D行有两个"\r\n\r\n";2)A行结尾没有\r\n;3)B行结尾有\r\n;4)C行结尾没有\r\n.  
  18. // 下面测试一下这4个特点究竟哪个会对HttpSendRequest的调用产生影响.  
  19. Test1: // A行结尾有\r\n  
  20.     LPCTSTR lpHeader = _T("GET /img/baidu_sylogo1.gif /HTTP/1.1\r\n")_T("Referer: http://www.baidu.com/")_T("Host: www.baidu.com")_T("\r\n\r\n");  
  21.     // HttpSendRequest返回0, dwErr = 12150, 含义ERROR_HTTP_HEADER_NOT_FOUND:The requested header could not be located.  
  22. Test2: // A/B/C行结尾没有\r\n  
  23.     LPCTSTR lpHeader = _T("GET /img/baidu_sylogo1.gif /HTTP/1.1")_T("Referer: http://www.baidu.com/")_T("Host: www.baidu.com")_T("\r\n\r\n");  
  24.     // HttpSendRequest返回1, dwErr = 0  
  25. Test3: // D行结尾一个\r\n  
  26.     LPCTSTR lpHeader = _T("GET /img/baidu_sylogo1.gif /HTTP/1.1")_T("Referer: http://www.baidu.com/")_T("Host: www.baidu.com")_T("\r\n");  
  27.     // HttpSendRequest返回1, dwErr = 0  
  28. Test4: // D行结尾没有\r\n  
  29.     LPCTSTR lpHeader = _T("GET /img/baidu_sylogo1.gif /HTTP/1.1")_T("Referer: http://www.baidu.com/")_T("Host: www.baidu.com");  
  30.     // HttpSendRequest返回1, dwErr = 0   
 从以上4个测试可以看出,HttpSendRequest的第二个参数header是一个字符串,A行必须不能有\r\n,其它行可以有,也可以没有.
 在测试中还发现,仅仅只有A行会导致HttpSendRequest调用失败,必须得有B行.
 其实lpHeader的值A行刚好对应HttpOpenRequest的参数lpszVerb,lpszObjectName和lpszVersion;B行对应参数lpszReferer.所以,#if 2...endif 还可以用下面的代码代替:
 
 
    
  1. #if 3 
  2.     hOpenRequestHandle = ::HttpOpenRequest(hConnectHandle, NULL, NULL, NULL, NULL, NULL, dwFlag, dwContext); 
  3.     LPCTSTR lpHeader =  _T("GET /img/baidu_sylogo1.gif /HTTP/1.1")_T("Referer: http://www.baidu.com/"); 
  4.     DWORD dwLen = _tcslen(lpHeader); 
  5.     bRet = ::HttpAddRequestHeaders(hOpenRequestHandle, lpHeader, nLen, HTTP_ADDREQ_FLAG_REPLACE|HTTP_ADDREQ_FLAG_ADD);//返回1 
  6.     bRet = ::HttpSendRequest(hOpenRequestHandle, NULL, 0, NULL, 0);//返回1 
  7. #endif   
以上这些测试都是在VS2008系统中测试出来的,如果有谁发现HttpSendRequest发送的HTTP头结构文档及其它特点,还请告诉我,不胜感激.
 

 参考这里