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;
}
时间: 2024-11-19 17:03:26

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

如何使用multipart/form-data格式上传文件(POST请求时,数据是放在请求体内,而不是请求头内,在html协议中,用 “\r\n” 换行,而不是 “\n”)

在网络编程过程中需要向服务器上传文件.Multipart/form-data是上传文件的一种方式. Multipart/form-data其实就是浏览器用表单上传文件的方式.最常见的情境是:在写邮件时,向邮件后添加附件,附件通常使用表单添加,也就是用multipart/form-data格式上传到服务器. 表单形式上传附件 具体的步骤是怎样的呢? 首先,客户端和服务器建立连接(TCP协议). 第二,客户端可以向服务器端发送数据.因为上传文件实质上也是向服务器端发送请求. 第三,客户端按照符合“m

django Form组件 上传文件

上传文件 注意:FORM表单提交文件要有一个参数enctype="multipart/form-data" 普通上传: urls: url(r'^f1/',views.f1), url(r'^f2/',views.f2), views: def f1(request): if request.method == "GET": return render(request,'f1.html') else: import os #导入os模块 #request.get /

笔谈HTTP Multipart POST请求上传文件

公司一做iOS开发的同事用HTTP Multipart POST请求上传语音数据,但是做了两天都没搞定,项目经理找到我去帮忙弄下.以前做项目只用过get.post,对于现在这个跟服务器交互的表单请求我没有做过,但是程序员学习能力还是要有的,解决问题的方法和经验是很重要的.做过2000万用户量的业务sdk的开发,这点东西自然不在话下,优秀的程序员就是要有解决问题的能力与方法. 1) 接口地址 接口地址为:http://ip:port/upload 2) UploadRequest消息定义 Form

[转]如何使用multipart/form-data格式上传文件

form表单中enctype="multipart/form-data"的意思,是设置表单的MIME编码.默认情况,这个编码格式是"application/x-www-form-urlencoded",不能用于文件上传:只有使用了multipart/form-data,才能完整的传递文件数据. 有时,在网络编程过程中需要向服务器上传文件.Multipart/form-data是上传文件的一种方式. Multipart/form-data其实就是浏览器用表单上传文件的

jquery.form附件上传的 $.handleError 、以及 $.httpData报错原因及解决方法

jquery.form.js上传出现$.handleError  .以及  $.httpData错误 原因: 首先,jquery1.4以后的版本不在支持这两个方法. 解决方法: 添加 (在jquery.form.js)中添加如下方法: $.httpData=function( xhr, type, s ) { var ct = xhr.getResponseHeader( 'content-type'), xml = type == 'xml' || !type && ct &&a

解决python发送multipart/form-data请求上传文件的问题

服务器接收文件时,有时会使用表单接收的方式,这意味着我们需要使用Python的requests上传表单数据和文件. 常用的方式一般如下: data = { 'name': 'nginx' } files = {'file': open("abc.csv", 'rb')} response = requests.post(url, data=data, files=files) files是封装好的参数,直接包括了文件内容,文件名,格式等,data则是表单内容,但这样做有一个问题,文件是

使用python或robotframework调multipart/form-data接口上传文件

这几天调一个multipart/form-data类型的接口,遇到点小阻碍.之前同事有使用urllib库写了个类似的方法实现,比较长,想要改的时候发现不太好使.在网上查找发现用requests库做这个更强大.下面具体介绍一下python-requests及robotframework-RequestsLibrary实现multipart/form-data接口上传文件.1.从fiddler查看接口长这样:Header: WebForms: 2.python-requests实现 #!/usr/b

aspx 文件上传和下载,多文件上传

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="MultiFileUpload.aspx.cs"  Inherits="MultiFileUpload"%> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org

微信企业号-上传、获取临时素材文件

(转 https://www.cnblogs.com/phonecom/p/08859d91a2dac3c409f5859dcb36cb48.html) 上传.获取临时素材文件,媒体文件类型有图片(image).语音(voice).视频(video),普通文件(file) ,这里以上传.下载图片为例 上传临时素材文件 根据开发文档,可以看出,需要三个参数access_token.type.media,access_token和type容易解决,media的话就要写一个表单上传过来 表单如下: <