2017-12-19 14 views
1

일부 XML 데이터 (http://freecite.library.brown.edu/welcome/api_instructions)를 가져 오기 위해 API에 POST 요청을해야합니다. 이 curl와 함께 잘 작동 : wininet을 사용하여 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를 사용하여 유사한 말았을하려고하고있다. , availableBytes이 결과 0 나옵니다도 InternetQueryDataAvailable에 대한 호출 후 for 루프에 들어가기 전에

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; 
} 

문제는, 나는 마침내 응답으로 빈 문자열을 그만 둘입니다 : 이것은 내 코드입니다 반면 XML 응답을 기대하고있었습니다.

누구나 내가 잘못하고있는 것을 나에게 지적 할 수 있으며 어떻게 고칠 수 있습니까?

+0

당신은 API 호출 중 하나에서 처리 오류를 안하고을 반환해야합니다. 그들 중 누구라도 실패 할 수 있고 당신은 그것을 알지 못할 것입니다. 또한 응답 데이터를 읽기 전에'HttpQueryInfo()'를 사용하여 요청이 실제로 성공했는지 확인하기 위해 서버의 응답 코드를 얻을 수있다. –

+0

동의했다, 나는'GetLastError()'호출을 추가하고 그것이 송신 요청 자체에서 실패하고있는 것을 발견했다. – SexyBeast

답변

1

InternetConnect은 서버 이름 또는 IP 주소를 필요로하므로 주소에 "http://"을 포함하지 마십시오. 변경 대상 :

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

data에는 UTF-8을 사용하십시오. WinAPI 함수의 다른 매개 변수는 UTF-16을 올바르게 사용하므로 필요한 변환을 자동으로 수행합니다.

변경 헤더 : 당신이 accept을 (그 자리에 NULL 사용), 결과는있을 수 지정하지 않은 경우

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

accept, HttpOpenRequest

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

주를 통해 전송한다 일반 html.

아래의 예는 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