HTTP使用 multipart/form-data 上传多个字段(包括文件字节流 octet-stream)

Posted Love流浪的猪

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HTTP使用 multipart/form-data 上传多个字段(包括文件字节流 octet-stream)相关的知识,希望对你有一定的参考价值。

自己用到的一个向服务器上传多个字段的实例,代码不全,仅做参考。

用的是WinINet,上传的字段中包括文件字节流

 

/*
PHttpRequest中自行组装body之后,HttpSendRequest中自己判断body长度时,
由于文件内容中存在 \0,所以body长度计算错误,导致上传的文件内容不正确,直接指定body的长度也不行...
PHttpRequest中未使用InternetWriteFile,
*/

int UpdateToServer2(stResumeInfo st, int& candId, CString& szUpdateTime, int& nFileSize)
{
    HINTERNET hSession=0;
    HINTERNET hConnect=0;
    HINTERNET hRequest=0;
    
    DWORD dwNumberOfBytesWritten=0;
    DWORD dwBytesSend=0;
    DWORD dwFlag = 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)
    {
        LOG_INFO(L"----- updateResume InternetOpen return 0 !!! GetLastError: %d------", GetLastError());
        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);
        LOG_INFO(L"----- updateResume InternetConnect return 0 !!! GetLastError: %d------", GetLastError());
        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);
        LOG_INFO(L"----- updateResume HttpOpenRequest return 0 !!! GetLastError: %d------", GetLastError());
        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);

    //验证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);
        LOG_INFO(L"----- updateResume HttpSendRequestEx return 0 !!! GetLastError: %d------", GetLastError());
        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表示成功, 
    }if(!root["data"].isNull())
    {
        Json::Value data = root["data"];
         int userId = data["userId"].asInt();
        candId = data["candId"].asInt();
        int resumeId = data["resId"].asInt();
        nFileSize = data["resSize"].asInt();
    }

    InternetCloseHandle(hRequest);
    InternetCloseHandle(hConnect);
    InternetCloseHandle(hSession);
   return 0;
}

 

以上是关于HTTP使用 multipart/form-data 上传多个字段(包括文件字节流 octet-stream)的主要内容,如果未能解决你的问题,请参考以下文章

MVC 简单实现图片上传

MVC 简单实现图片上传

将图像发布到 asp.net API 2 和 angular 2

springMVC怎么把结果集写入Excel并导出

求springmvc导入导出Excel的例子,越全面越好。

postman中form-datax-www-form-urlencodedrawbinary的区别