2017-12-19 19 views
1

XMLデータ(http://freecite.library.brown.edu/welcome/api_instructions)を取得するために、APIにPOSTリクエストを行う必要があります。これは正常に動作しますcurlwininetを使用してPOST要求応答を取得できません

curl -H "Accept: application/xml" --data "citation=Udvarhelyi, I.S., Gatsonis, C.A., Epstein, A.M., Pashos, C.L., Newhouse, J.P. and McNeil, B.J. Acute Myocardial Infarction in the Medicare population: process of care and clinical outcomes. Journal of the American Medical Association, 1992; 18:2530-2536. " http://freecite.library.brown.edu:80/citations/create 

私はWin32 SDKを使用して同様のことをしようとしています。これは私のコードです:

void LoadData() 
{ 
    wil::unique_hinternet hInternet(InternetOpen(L"Dummy", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0)); 
    wil::unique_hinternet hConnect(InternetConnect(hInternet.get(), L"http://freecite.library.brown.edu", 80, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0)); 
    wil::unique_hinternet hRequest(HttpOpenRequest(hConnect.get(), L"POST", L"/citations/create", NULL, NULL, NULL, NULL, NULL)); 
    wstring data = L"citation=Udvarhelyi, I.S., Gatsonis, C.A., Epstein, A.M., Pashos, C.L., Newhouse, J.P. and McNeil, B.J. Acute Myocardial Infarction in the Medicare population: process of care and clinical outcomes. Journal of the American Medical Association, 1992; 18:2530-2536."; 
    PCWSTR szHeaders = L"Accept: application/xml"; 

    HttpSendRequest(hRequest.get(), szHeaders, 0, (LPVOID)data.c_str(), static_cast<int>(data.length())); 

    DWORD availableBytes = 0; 
    InternetQueryDataAvailable(hRequest.get(), &availableBytes, 0, 0); 
    PBYTE outputBuffer = (PBYTE)HeapAlloc(GetProcessHeap(), 0, availableBytes); 
    PBYTE nextBytes = outputBuffer; 
    DWORD bytesUsed = 0; // number of used bytes. 
    while (availableBytes) 
    { 
     DWORD downloadedBytes; 
     InternetReadFile(hRequest.get(), nextBytes, availableBytes, &downloadedBytes); 
     bytesUsed = bytesUsed + downloadedBytes; 

     InternetQueryDataAvailable(hRequest.get(), &availableBytes, 0, 0); 
     if (availableBytes > 0) 
     { 
      // lazy buffer growth here. Only alloc for what we need. could be optimized if we end up with huge payloads (>10MB). 
      // otherwise, this is good enough. 
      outputBuffer = (PBYTE)HeapReAlloc(GetProcessHeap(), 0, outputBuffer, bytesUsed + availableBytes); 
      nextBytes = outputBuffer + bytesUsed; // careful, pointer might have moved! Update cursor. 
     } 
    } 

    // Convert outputed XML to wide char 
    int size_needed = MultiByteToWideChar(CP_UTF8, 0, (PCCH)outputBuffer, bytesUsed, NULL, 0); 
    std::wstring wstrTo(size_needed, 0); 
    MultiByteToWideChar(CP_UTF8, 0, (PCCH)outputBuffer, bytesUsed, &wstrTo[0], size_needed); 

    wstring res = wstrTo; 
} 

問題は、さえInternetQueryDataAvailableを呼び出した後、forループに入る前に、あるavailableBytesは、結果として0に出てくる、私は最終的にレスポンスとして空の文字列を取得して終了します私はXMLレスポンスを期待していました。

私は間違って何をしているのか誰に教えてもらえますか?

+0

を返す必要があります。それらのいずれかが失敗する可能性があり、あなたはそれを知らないでしょう。また、 'HttpQueryInfo()'を使ってサーバーの応答コードを取得し、応答データを読み取る前に要求が実際に成功したことを確認することができます。 –

+0

合意して、私は 'GetLastError()'呼び出しを追加し、送信要求自体に失敗していることを発見しました。 – SexyBeast

答えて

1

InternetConnectは、サーバー名またはIPアドレスを想定しているため、アドレスに"http://"を含めないでください。変更:

InternetConnect(handle, L"freecite.library.brown.edu"...); 

dataにはUTF-8を使用してください。 WinAPI関数のその他のパラメータは、UTF-16を使用して正しく、必要な変換を自動的に行います。

変更ヘッダ:

std::wstring szHeaders = L"Content-Type: application/x-www-form-urlencoded\r\n"; 

acceptHttpOpenRequest

const wchar_t *accept[] = { L"text/xml", NULL }; 
HINTERNET hrequest = HttpOpenRequest(hconnect, L"POST", L"/citations/create", 
    NULL, NULL, accept, 0, 0); 

注意、あなたが(その場所にNULLを使用)acceptを指定しない場合、結果はですることができ介して送信されるべきプレーンhtml。

次の例では、あなたはAPI呼び出しのいずれかに任意のエラー処理を行っていないXMLデータに

std::wstring get_utf16(const std::string &str); 
std::string get_utf8(const std::wstring &wstr); 

int main() 
{ 
    HINTERNET hsession = NULL; 
    HINTERNET hconnect = NULL; 
    HINTERNET hrequest = NULL; 
    std::wstring result; 
    std::wstring szHeaders = L"Content-Type: application/x-www-form-urlencoded\r\n"; 
    std::wstring data_w = L"citation=Udvarhelyi, I.S., Gatsonis, C.A., Epstein, A.M., Pashos, C.L., Newhouse, J.P. and McNeil, B.J. Acute Myocardial Infarction in the Medicare population: process of care and clinical outcomes. Journal of the American Medical Association, 1992; 18:2530-2536."; 
    std::string data = get_utf8(data_w); 

    hsession = InternetOpen(L"appname", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); 
    if(!hsession) 
     goto cleanup; 

    hconnect = InternetConnect(hsession, L"freecite.library.brown.edu", 
     INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0); 
    if(!hconnect) 
     goto cleanup; 

    const wchar_t *accept[] = { L"text/xml", NULL }; 
    hrequest = HttpOpenRequest(hconnect, L"POST", L"/citations/create", 
     NULL, NULL, accept, 0, 0); 
    if(!hrequest) 
     goto cleanup; 
    BOOL sent = HttpSendRequest(hrequest, szHeaders.c_str(), szHeaders.size(), 
     &data[0], data.size()); 

    if(sent) 
    { 
     DWORD blocksize = 4096; 
     DWORD received = 0; 
     std::string temp; 
     std::string block(blocksize, 0); 
     while(InternetReadFile(hrequest, &block[0], blocksize, &received) && received) 
     { 
      block.resize(received); 
      temp += block; 
     } 
     result = get_utf16(temp); 
     std::wcout << result << std::endl; 
    } 

cleanup: 
    if(hrequest) InternetCloseHandle(hrequest); 
    if(hconnect) InternetCloseHandle(hconnect); 
    if(hsession) InternetCloseHandle(hsession); 
    return 0; 
} 

std::wstring get_utf16(const std::string &str) 
{ 
    if(str.empty()) return std::wstring(); 
    int sz = MultiByteToWideChar(CP_UTF8, 0, &str[0], -1, 0, 0); 
    std::wstring res(sz, 0); 
    MultiByteToWideChar(CP_UTF8, 0, &str[0], -1, &res[0], sz); 
    return res; 
} 

std::string get_utf8(const std::wstring &wstr) 
{ 
    int sz = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], -1, 0, 0, 0, 0); 
    std::string res(sz, 0); 
    WideCharToMultiByte(CP_UTF8, 0, &wstr[0], -1, &res[0], sz, 0, 0); 
    return res; 
} 
+0

絶対的な魅力のように機能します!どうもありがとうございます!最初に「http://」を追加することで何が問題になるのか説明できますか? – SexyBeast

+0

['InternetConnect'](https://msdn.microsoft.com/en-us/library/windows/desktop/aa384363(v = vs.85).aspx)には、ホスト名またはIPアドレスが必要です。 'InternetOpen'は完全なURLを必要とします。 –

+0

ああ。とった。ありがとう! – SexyBeast

関連する問題