HTTP上传数据 :表单,二进制数据(multipart/form-data application/octet-stream boundary)

使用WinINet

一个较简单的例子:上传头像

void CBackstageManager::UpdateAvatarThreadProc(LPVOID params)
{
    stForThread* pSt = (stForThread* )params;

    HINTERNET hSession=0;
    HINTERNET hConnect=0;
    HINTERNET hRequest=0;

    DWORD dwNumberOfBytesWritten=0;
    DWORD dwBytesSend=0;
    DWORD dwFlag = 0;

    hSession=InternetOpen(_T("Mozilla/5.0 (Windows NT 6.1; WOW64; rv:22.0) Gecko/20100101 Firefox/22.0"),
        INTERNET_OPEN_TYPE_PRECONFIG,   0, INTERNET_INVALID_PORT_NUMBER,  0);
    if (0==hSession)
    {
        SAFE_DELETE(pSt);
        NotifyManager::Instance().Notify(TaskListener::TASK_TYPE_UPDATE_AVATAR_RESULT, TaskListener::TASK_STATUS_TIMEOUT,0);
        return ;
    }


    unsigned short port_ = INTERNET_DEFAULT_HTTP_PORT;
    if (CConfig::IsHttps()) //外网用HTTPS
    {
        port_ = INTERNET_DEFAULT_HTTPS_PORT;
    }
    //INTERNET_SERVICE_HTTP : HTTP HTTPS
    hConnect=InternetConnect(hSession, CConfig::URL_HOST, port_, _T(""), _T(""), INTERNET_SERVICE_HTTP,  0,   0);  //URL_HOST不能带http://
    if (0==hConnect)
    {
        SAFE_DELETE(pSt);
        NotifyManager::Instance().Notify(TaskListener::TASK_TYPE_UPDATE_AVATAR_RESULT, TaskListener::TASK_STATUS_TIMEOUT,0);
        InternetCloseHandle(hSession);
        return ;
    }

    dwFlag=INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_AUTH | INTERNET_FLAG_NO_UI ;
    if (CConfig::IsHttps()) //外网用HTTPS
        dwFlag |= INTERNET_FLAG_SECURE|INTERNET_FLAG_IGNORE_CERT_CN_INVALID|INTERNET_FLAG_IGNORE_CERT_DATE_INVALID|INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP ;
    hRequest=HttpOpenRequest(hConnect, _T("POST"),  UPDATE_AVATAR_URL,
        HTTP_VERSION,
        0,                //Referrer
        0,                //AcceptTypes 
        dwFlag,
        0);
    if (0==hRequest)
    {
        InternetCloseHandle(hConnect);
        InternetCloseHandle(hSession);
        SAFE_DELETE(pSt);
        NotifyManager::Instance().Notify(TaskListener::TASK_TYPE_UPDATE_AVATAR_RESULT, TaskListener::TASK_STATUS_TIMEOUT,0);
        return ;
    }

    //设置Header
    CString content_type = TEXT("Content-Type: multipart/form-data; boundary=");
    content_type.Append(_T(ABOUNDARY));
    HttpAddRequestHeaders(hRequest,content_type,-1,HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE);

    //验证cid和token
    CString szAuthorization = TEXT("Authorization: ");
    szAuthorization.Append(CBackstageManager::GetInstance().GetAuthorizationString());
    HttpAddRequestHeaders(hRequest,szAuthorization, -1,HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE); 
    szAuthorization = TEXT("Agent-Info: ");
    szAuthorization.Append(CBackstageManager::GetInstance().GetAgentInfo()); 
    HttpAddRequestHeaders(hRequest,szAuthorization, -1,HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE); 

    //读取文件内容和长度
    HANDLE hFile;
    hFile=CreateFile(pSt->sTmp,  GENERIC_READ,   FILE_SHARE_READ|FILE_SHARE_WRITE, 0,
        OPEN_EXISTING,  FILE_ATTRIBUTE_NORMAL,  0);
    DWORD dwFileSize=GetFileSize(hFile,0);
    BYTE* lpBuffer=(BYTE*)VirtualAlloc(0,dwFileSize,MEM_COMMIT,PAGE_READWRITE);
    if (0==lpBuffer)
    {
        InternetCloseHandle(hRequest);
        InternetCloseHandle(hConnect);
        InternetCloseHandle(hSession);
        SAFE_DELETE(pSt);
        NotifyManager::Instance().Notify(TaskListener::TASK_TYPE_UPDATE_AVATAR_RESULT, TaskListener::TASK_STATUS_ERROR,0);
        return ;
    }
    DWORD dwRead;
    ReadFile(hFile,lpBuffer,dwFileSize,&dwRead,0);
    CloseHandle(hFile);


    char first_boundary[64]={0};
    char delimiter[64]={0};
    char end_boundary[64]={0};
    sprintf_s(first_boundary,"--%s\r\n",ABOUNDARY);
    sprintf_s(delimiter,"\r\n--%s\r\n",ABOUNDARY);
    sprintf_s(end_boundary,"\r\n--%s--\r\n",ABOUNDARY);

    //LPSTR rn="\r\n"; //HTTP POST数据中的换行必须使用\r\n
    //计算body长度
    char content_dispos[64]={0};
    int length = strlen(first_boundary);

    CString stmName = PathFindFileName(pSt->sTmp);
    char content_dispos2[256]={0};
    if(stmName.GetLength() > 32)
    {
        stmName = stmName.Left(28) + PathFindExtension(stmName); //防止content_dispos2越界
    }
    std::string name = CT2A(stmName, CP_UTF8);
    sprintf_s(content_dispos2, "Content-Disposition: form-data; name=\"image\"; filename=\"%s\"\r\n", name.c_str());
    LPSTR content_type2="Content-Type: application/octet-stream\r\n\r\n";

    //加上File长度
    length +=dwFileSize + strlen(content_dispos2) +strlen(content_type2);
    length += strlen(end_boundary);

    INTERNET_BUFFERS BufferIn;
    BufferIn.dwStructSize = sizeof( INTERNET_BUFFERS );
    BufferIn.Next = NULL; 
    BufferIn.lpcszHeader = NULL;
    BufferIn.dwHeadersLength = 0;
    BufferIn.dwHeadersTotal = 0;
    BufferIn.lpvBuffer = NULL;                
    BufferIn.dwBufferLength = 0;
    BufferIn.dwBufferTotal = length;
    BufferIn.dwOffsetLow = 0;
    BufferIn.dwOffsetHigh = 0;

    if (!HttpSendRequestEx(hRequest,&BufferIn,0,0,0))
    {
        DWORD a = GetLastError();
        InternetCloseHandle(hRequest);
        InternetCloseHandle(hConnect);
        InternetCloseHandle(hSession);
        SAFE_DELETE(pSt);
        NotifyManager::Instance().Notify(TaskListener::TASK_TYPE_UPDATE_AVATAR_RESULT, TaskListener::TASK_STATUS_TIMEOUT,0);
        return ;
    }

    //上传body
    InternetWriteFile(hRequest,(byte*)first_boundary,strlen(first_boundary),&dwNumberOfBytesWritten); //first boundary

    //上传文件
    InternetWriteFile(hRequest,(byte*)content_dispos2,strlen(content_dispos2),&dwNumberOfBytesWritten);
    InternetWriteFile(hRequest,(byte*)content_type2,strlen(content_type2),&dwNumberOfBytesWritten);
    InternetWriteFile(hRequest,lpBuffer,dwFileSize,&dwNumberOfBytesWritten);

    //last boundary
    InternetWriteFile(hRequest,(byte*)end_boundary,strlen(end_boundary),&dwNumberOfBytesWritten);

    if(!HttpEndRequest(hRequest,0,0,0))
        HttpEndRequest(hRequest,0,0,0);

    VirtualFree(lpBuffer,0,MEM_RELEASE);

    //获取返回数据
    std::stringstream sstream;
    CParseResumeTask::GetResponse(&sstream, hRequest, 5000);
    Json::Value root;
    Json::Reader reader;
    reader.parse(sstream.str(), root);
    int code = -1;
    if(!root["code"].isNull())
    {
        code = root["code"].asInt(); //0表示成功, 
    }
    if(!root["msg"].isNull())
    {
        std::string s = root["msg"].asString();
        CString sss = CA2T(s.c_str(), CP_UTF8);
    }
    CString szAvatarUrl;
    if(!root["data"].isNull())
    {
        szAvatarUrl = CBackstageManager::GetJsonString(root, "data");
        CBackstageManager::GetInstance().SetAvatarDownUrl(szAvatarUrl);
    }

    InternetCloseHandle(hRequest);
    InternetCloseHandle(hConnect);
    InternetCloseHandle(hSession);

    if(code == 0)
    {
        {
            CBackstageManager::GetInstance().SetAvatarLocalPath(pSt->sTmp);
            CSaveAccount::SaveAvatarUrl(CBackstageManager::GetInstance().GetUserId(), szAvatarUrl, pSt->sTmp);
        }

        NotifyManager::Instance().Notify(TaskListener::TASK_TYPE_UPDATE_AVATAR_RESULT, TaskListener::TASK_STATUS_OK,0); 
    }
    else
    {
        if (code == 7 || code == 8)
            CBackstageManager::NotifyUnlogged(code == 8);
        else
            NotifyManager::Instance().Notify(TaskListener::TASK_TYPE_UPDATE_AVATAR_RESULT, TaskListener::TASK_STATUS_ERROR,0);
    }

    SAFE_DELETE(pSt);
}

较麻烦的实例:上传简历文件,及各项参数

int CParseResumeTask::UpdateToServer2(const stResumeInfo& st, int& candId, CString& szUpdateTime, int& nFileSize, int& reposedCode)
{
    HINTERNET hSession=0;
    HINTERNET hConnect=0;
    HINTERNET hRequest=0;
    
    DWORD dwNumberOfBytesWritten=0;
    DWORD dwBytesSend=0;
    DWORD dwFlag = 0;
    reposedCode = 0;

    candId = 0;
    szUpdateTime.Empty();
    hSession=InternetOpen(_T("Mozilla/5.0 (Windows NT 6.1; WOW64; rv:22.0) Gecko/20100101 Firefox/22.0"),
                                 INTERNET_OPEN_TYPE_PRECONFIG,   0, INTERNET_INVALID_PORT_NUMBER,  0);
    if (0==hSession)
    {
        reposedCode = -1;
        return 0;
    }

    unsigned short port_ = INTERNET_DEFAULT_HTTP_PORT;
    if (CConfig::GetServerType() == 1) //外网用HTTPS
    {
        port_ = INTERNET_DEFAULT_HTTPS_PORT;
    }
    hConnect=InternetConnect(hSession, CConfig::URL_HOST, port_, _T(""), _T(""), INTERNET_SERVICE_HTTP,  0,   0);  //URL_HOST不能带http://
    if (0==hConnect)
    {
        InternetCloseHandle(hSession);
        reposedCode = -2;
        return 0;
    }

    dwFlag=INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_AUTH | INTERNET_FLAG_NO_UI ;
    if (CConfig::GetServerType() == 1) //外网用HTTPS
        dwFlag |= INTERNET_FLAG_SECURE|INTERNET_FLAG_IGNORE_CERT_CN_INVALID|INTERNET_FLAG_IGNORE_CERT_DATE_INVALID|INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP ;
#ifdef UP_FILE_TO_SEVER
    hRequest=HttpOpenRequest(hConnect, _T("POST"),  RESUME_UPLOAD_URL,  HTTP_VERSION,    0,  0,  dwFlag,  0);//old 
#else
    hRequest=HttpOpenRequest(hConnect, _T("POST"),  RESUME_UPLOAD_URL_NEW,  HTTP_VERSION,    0,  0,  dwFlag,  0);
#endif
    if (0==hRequest)
    {
        InternetCloseHandle(hConnect);
        InternetCloseHandle(hSession);
        reposedCode = -3;
        return 0;
    }

    if (m_bCancel) return 0;

    //设置Header
    //TCHAR content_type[128]={0};
    //_stprintf_s(content_type,TEXT("Content-Type: multipart/form-data; boundary=%s"), _T(ABOUNDARY));
    CString content_type = TEXT("Content-Type: multipart/form-data; boundary=");
    content_type.Append(_T(ABOUNDARY));
    HttpAddRequestHeaders(hRequest,content_type,-1,HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE);

    //如果当前用户ID与预存的用户ID不一致(已登出,或已登录新账户),不再上传
    int userid = CBackstageManager::GetInstance().GetUserId();
    if (m_nCurUserid != userid)
        return 0;

    //验证cid和token
     CString szAuthorization = TEXT("Authorization: ");
    szAuthorization.Append(/*CA2T(s64, CP_UTF8)*/CBackstageManager::GetInstance().GetAuthorizationString());
    HttpAddRequestHeaders(hRequest,szAuthorization, -1,HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE); 
    szAuthorization = TEXT("Agent-Info: ");
    szAuthorization.Append(CBackstageManager::GetInstance().GetAgentInfo()); 
    HttpAddRequestHeaders(hRequest,szAuthorization, -1,HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE); 


#ifdef UP_FILE_TO_SEVER
    //读取文件内容和长度
    HANDLE hFile;
    hFile=CreateFile(st.strFilePath,  GENERIC_READ,   FILE_SHARE_READ|FILE_SHARE_WRITE, 0,
        OPEN_EXISTING,  FILE_ATTRIBUTE_NORMAL,  0);
    DWORD dwFileSize=GetFileSize(hFile,0);
    BYTE* lpBuffer=(BYTE*)VirtualAlloc(0,dwFileSize,MEM_COMMIT,PAGE_READWRITE);
    if (0==lpBuffer)
    {
        InternetCloseHandle(hRequest);
        InternetCloseHandle(hConnect);
        InternetCloseHandle(hSession);
        LOG_INFO(L"----- updateResume VirtualAlloc return 0 !!! GetLastError: %d------", GetLastError());
        return 0;
    }
    DWORD dwRead;
    ReadFile(hFile,lpBuffer,dwFileSize,&dwRead,0);
    CloseHandle(hFile);
#endif

    char first_boundary[64]={0};
    char delimiter[64]={0};
    char end_boundary[64]={0};
    sprintf_s(first_boundary,"--%s\r\n",ABOUNDARY);
    sprintf_s(delimiter,"\r\n--%s\r\n",ABOUNDARY);
    sprintf_s(end_boundary,"\r\n--%s--\r\n",ABOUNDARY);

    //LPSTR rn="\r\n"; //HTTP POST数据中的换行必须使用\r\n
    std::map<std::string, std::string> ssmap;
    GetResumeInfoMap(st, ssmap); ////上传给后台必须使用字符串,不能用整型

    //计算body长度
    char content_dispos[64]={0};
    std::map<std::string, std::string>::iterator it = ssmap.begin();
    int length = strlen(first_boundary);
    for(; it != ssmap.end(); it++)
    {
        memset(content_dispos, 0, sizeof(content_dispos));
        sprintf_s(content_dispos,"Content-Disposition: form-data; name=\"%s\"\r\n\r\n", it->first.c_str());
        length += strlen(content_dispos);
        length += it->second.length();
        length += strlen(delimiter);
    }

#ifdef UP_FILE_TO_SEVER
    char content_dispos2[256]={0};
    CString stmName = st.file_name;
    if(stmName.GetLength() > 32)
    {
        stmName = stmName.Left(28) + PathFindExtension(stmName); //防止content_dispos2越界
    }
    std::string name = CT2A(stmName, CP_UTF8);
    sprintf_s(content_dispos2, "Content-Disposition: form-data; name=\"file\"; filename=\"%s\"\r\n", name.c_str());
    LPSTR content_type2="Content-Type: application/octet-stream\r\n\r\n";

    //加上File长度
    length +=dwFileSize + strlen(content_dispos2) +strlen(content_type2);
#else
    length -= strlen(delimiter);
#endif
    length += strlen(end_boundary);

    if (m_bCancel) return FALSE;
     INTERNET_BUFFERS BufferIn;
    BufferIn.dwStructSize = sizeof( INTERNET_BUFFERS );
    BufferIn.Next = NULL; 
    BufferIn.lpcszHeader = NULL;
    BufferIn.dwHeadersLength = 0;
    BufferIn.dwHeadersTotal = 0;
    BufferIn.lpvBuffer = NULL;                
    BufferIn.dwBufferLength = 0;
    BufferIn.dwBufferTotal = length;
    BufferIn.dwOffsetLow = 0;
    BufferIn.dwOffsetHigh = 0;

    if (!HttpSendRequestEx(hRequest,&BufferIn,0,0,0))
    {
        InternetCloseHandle(hRequest);
        InternetCloseHandle(hConnect);
        InternetCloseHandle(hSession);
        reposedCode = -4;
        return 0;
    }

    //上传body
    InternetWriteFile(hRequest,(byte*)first_boundary,strlen(first_boundary),&dwNumberOfBytesWritten); //first boundary
    int count = ssmap.size();
    std::map<std::string, std::string>::iterator iter = ssmap.begin();
    for(int index = 0; iter != ssmap.end(); iter++, index++)
    {
        memset(content_dispos, 0, sizeof(content_dispos));
        sprintf_s(content_dispos,"Content-Disposition: form-data; name=\"%s\"\r\n\r\n", iter->first.c_str());
        InternetWriteFile(hRequest,(byte*)content_dispos, strlen(content_dispos),&dwNumberOfBytesWritten);

        std::string value = iter->second;
         InternetWriteFile(hRequest,(byte*)value.c_str(), value.length(), &dwNumberOfBytesWritten);

#ifndef UP_FILE_TO_SEVER
         if(index != (count-1))
 #endif
            InternetWriteFile(hRequest,(byte*)delimiter,strlen(delimiter),&dwNumberOfBytesWritten); 
    }

    if (m_bCancel) return 0;

#ifdef UP_FILE_TO_SEVER
    //上传文件
    InternetWriteFile(hRequest,(byte*)content_dispos2,strlen(content_dispos2),&dwNumberOfBytesWritten);
    InternetWriteFile(hRequest,(byte*)content_type2,strlen(content_type2),&dwNumberOfBytesWritten);
    InternetWriteFile(hRequest,lpBuffer,dwFileSize,&dwNumberOfBytesWritten);
#endif

    //last boundary
    InternetWriteFile(hRequest,(byte*)end_boundary,strlen(end_boundary),&dwNumberOfBytesWritten);

    if(!HttpEndRequest(hRequest,0,0,0))
    {
        int a = GetLastError();
        HttpEndRequest(hRequest,0,0,0);
    }

#ifdef UP_FILE_TO_SEVER
    VirtualFree(lpBuffer,0,MEM_RELEASE);
#endif
    if (m_bCancel) return 0;
    //获取返回数据
    std::stringstream sstream;
    GetResponse(&sstream, hRequest, 5000);
    Json::Value root;
    Json::Reader reader;
    reader.parse(sstream.str(), root);
    int code = -1;
    if(!root["code"].isNull())
    {
        code = root["code"].asInt(); //0表示成功, 
        reposedCode = code;
    }
    CString sss;
    if(!root["msg"].isNull())
    {
        std::string s = root["msg"].asString();
        sss = CA2T(s.c_str(), CP_UTF8);
    }
    if(!root["data"].isNull())
    {
        Json::Value data = root["data"];
         int userId = data["userId"].asInt();
        candId = data["candidateId"].asInt();
        int resumeId = data["resumeId"].asInt();
        nFileSize = data["resumeSize"].asInt();
        szUpdateTime = CParseResumeTask::GetJsonString(data, "updateTime");
        CString szResuName = CParseResumeTask::GetJsonString(data, "resumeName");   //resumeName=51job_丁奕聪(338664425).doc
        int resumeSize = data["resumeSize"].asInt();    //resumeSize=140155
    }

    InternetCloseHandle(hRequest);
    InternetCloseHandle(hConnect);
    InternetCloseHandle(hSession);
   
    if (code == 3002) //此候选人已存在(但简历不一样),返回UI提示是替换,还是导入?
    {
        return 2;
    }

    if(code==0 || code==3000)
        return 1;    //3000表示之前已上传过完全相同的简历,算成功.(会返回候选人ID )

    LOG_ERROR(L"-----上传数据失败,后台返回 code: %d,Msg:%s------", code, sss);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/pjl1119/p/8532193.html