zoukankan      html  css  js  c++  java
  • 使用Http协议Post上传文件

    转载:http://www.cnblogs.com/softidea/p/5745369.html

    转载:https://blog.csdn.net/huanongying131/article/details/78426219

    转载:https://blog.csdn.net/shaderdx/article/details/28406033

    转载:https://blog.csdn.net/yamahayamede/article/details/79561119(http post 上传文件格式)

    转载:https://blog.csdn.net/Ideality_hunter/article/details/82971483(示例)

    转载:https://blog.csdn.net/a29562268/article/details/53932582(MFC 支持 Https 示例)

    转载:http://www.cnso.org/197/3835.html

    转载:https://blog.csdn.net/u010256388/article/details/68491509

    1.使用场景

           公司产品需要做一个关于收集程序崩溃信息的模块(BugReport),需要客户端程序在崩溃发生后将崩溃日志以及转储文件发送到后台。

    2.http 格式

      multipart/form-data

            这又是一个常见的 POST 数据提交的方式。我们使用表单上传文件时,必须让 <form> 表单的enctype 等于 multipart/form-data。直接来看一个请求示例:

    BASHPOST http://www.example.com HTTP/1.1
    Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA
    
    ------WebKitFormBoundaryrGKCBY7qhFd3TrwA
    Content-Disposition: form-data; name="text"  name:key
    两个空行 
    
    
    title                                        value:title
    ------WebKitFormBoundaryrGKCBY7qhFd3TrwA
    Content-Disposition: form-data; name="file"; filename="chrome.png"
    Content-Type: image/png
    
    PNG ... content of chrome.png ...
    ------WebKitFormBoundaryrGKCBY7qhFd3TrwA--

    这个例子稍微复杂点。首先生成了一个 boundary 用于分割不同的字段,为了避免与正文内容重复,boundary 很长很复杂。然后 Content-Type 里指明了数据是以 multipart/form-data 来编码,本次请求的 boundary 是什么内容。消息主体里按照字段个数又分为多个结构类似的部分,每部分都是以 --boundary 开始,紧接着是内容描述信息,然后是回车,最后是字段具体内容(文本或二进制)。如果传输的是文件,还要包含文件名和文件类型信息。消息主体最后以 --boundary-- 标示结束。
    关于 multipart/form-data 的详细定义,请前往 rfc1867 查看。

    这种方式一般用来上传文件,各大服务端语言对它也有着良好的支持。

    上面提到的这两种 POST 数据的方式,都是浏览器原生支持的,而且现阶段标准中原生 <form> 表单也只支持这两种方式(通过 <form> 元素的 enctype 属性指定,默认为 application/x-www-form-urlencoded。其实 enctype 还支持 text/plain,不过用得非常少)。

    随着越来越多的 Web 站点,尤其是 WebApp,全部使用 Ajax 进行数据交互之后,我们完全可以定义新的数据提交方式,给开发带来更多便利。

     

    MFC代码:

    #include <iostream>
    #include <afxinet.h>
    #include <Windows.h>
    #include <atlbase.h>
    #include <shlwapi.h>
    #include <string>
    #include <vector>
    using namespace std;
    
    #pragma warning(disable : 4996)
    
    wstring Utf8ToUnicode(const char* szU8)
    {
        if (szU8 == NULL)
            return L"";
    
        if (strlen(szU8) == 0)
            return L"";
    
        //预转换,得到所需空间的大小;
        int wcsLen = ::MultiByteToWideChar(CP_UTF8, NULL, szU8, strlen(szU8), NULL, 0);
    
        //分配空间要给''留个空间,MultiByteToWideChar不会给''空间
        wchar_t* wszString = new wchar_t[wcsLen + 1];
    
        //转换
        ::MultiByteToWideChar(CP_UTF8, NULL, szU8, strlen(szU8), wszString, wcsLen);
    
        //最后加上''
        wszString[wcsLen] = '';
    
        wstring unicodeString = wszString;
    
        delete[] wszString;
        wszString = NULL;
    
        return unicodeString;
    }
    
    string UnicodeToASNI(const wchar_t* unicode)
    {
        if (unicode == NULL)
            return "";
    
        if (wcslen(unicode) == 0)
            return "";
    
        int len;
        len = WideCharToMultiByte(CP_ACP, 0, unicode, -1, NULL, 0, NULL, NULL);
        char* szUtf8 = (char*)malloc(len + 1);
        memset(szUtf8, 0, len + 1);
        WideCharToMultiByte(CP_ACP, 0, unicode, -1, szUtf8, len, NULL, NULL);
    
        string sRet = szUtf8;
        free(szUtf8);
        szUtf8 = NULL;
        return sRet;
    }
    
    //ANSI ---> Unicode
    std::wstring ANSIToUnicode(const string& str)
    {
        int  Length = ::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, NULL, 0);
    
        if (Length == 0) return NULL;
    
        wchar_t *  pUnicode = new  wchar_t[Length + 1];
    
        memset(pUnicode, 0, (Length + 1) * sizeof(wchar_t));
    
        ::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, (LPWSTR)pUnicode, Length);
    
        pUnicode[Length] = 0;
    
        wstring  wstr = (wchar_t*)pUnicode;
    
        delete[]  pUnicode;
        pUnicode = NULL;
    
        return  wstr;
    }
    
    string UnicodeToUtf8(const wstring& wstr)
    {
        // 预算-缓冲区中多字节的长度  
        int ansiiLen = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr);
        // 给指向缓冲区的指针变量分配内存  
        char *pAssii = (char*)malloc(sizeof(char)*ansiiLen);
        // 开始向缓冲区转换字节  
        WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, pAssii, ansiiLen, nullptr, nullptr);
        string ret_str = pAssii;
        free(pAssii);
        return ret_str;
    }
    
    
    BOOL CSRCMBugReportDlg::UploadHttpFile(const CString& strUploadFileURL, const CString & strCrashFilePath, bool isHttps)
    {
        ASSERT(strUploadFileURL != "");
    
        ASSERT(strCrashFilePath != "");
    
        CInternetSession session(L"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36", 0);
        CHttpConnection* pHttpConnection = NULL;
        CHttpFile* pHttpFile = NULL;
        try
        {
            DWORD ServerType = 0;
            CString strServer, strObject;
            INTERNET_PORT wPort;
            CFile file;
    
            if (AfxParseURL(strUploadFileURL, ServerType, strServer, strObject, wPort))
            {
                //打开本地待上传文件
                if (!file.Open(strCrashFilePath, CFile::modeRead | CFile::shareDenyWrite | CFile::typeBinary))//如果文件路径有中文必须用ANSIToUnicode转成宽字节
                {
                    CString errText;
                    errText.Format(L"打开本地文件%s失败", strCrashFilePath);
                    theLogger.TraceError(errText);
    
                    ::PostMessage(this->GetSafeHwnd(), WM_EXIT_BUGREPORT, 0, 0);//完成退出BugReport
                    return FALSE;
                }
    
                const int nTimeOut = 5000;//5秒超时
                session.SetOption(INTERNET_OPTION_CONNECT_TIMEOUT, nTimeOut); //重试之间的等待延时
                session.SetOption(INTERNET_OPTION_CONNECT_RETRIES, 1);   //重试1次数
    
                if (isHttps)
                {
                    pHttpConnection = session.GetHttpConnection(strServer, INTERNET_FLAG_SECURE, wPort, NULL, NULL); //连接Https服务器
                }
                else
                {
                    pHttpConnection = session.GetHttpConnection(strServer, wPort); //取得一个Http联接
                }
    
                if (pHttpConnection)
                {
    if(isHttps)
    {
    pHttpFile = pHttpConnection->OpenRequest(CHttpConnection::HTTP_VERB_POST,strObject,NULL,1
    NULL,NULL,INTERNET_FLAG_SECURE|
    INTERNET_FLAG_EXISTING_CONNECT|
    INTERNET_FLAG_RELOAD |
    INTERNET_FLAG_NO_CACHE_WRITE |
    INTERNET_FLAG_IGNORE_CERT_DATE_INVALID |
    INTERNET_FLAG_IGNORE_CERT_CN_INVALID |
    INTERNET_FLAG_NO_COOKIES
    );//打开请求 ,这几个标识都要加上
    }
    else
    { pHttpFile
    = pHttpConnection->OpenRequest(CHttpConnection::HTTP_VERB_POST, strObject); } if (pHttpFile) { /*szBoundary,任意的一个串,用以标识body中的数据*/ //该串需要够复杂,用以区别当前请求包中的数据 const char * szBoundary = "----------------------------096304854221961038114493"; /*构造头部*/ pHttpFile->AddRequestHeaders(L"Accept:*/*"); pHttpFile->AddRequestHeaders(L"Accept-Encoding:gzip, deflate"); //构造头中的Content-Type项,其中需要填上boundary CString szContentType = L"Content-Type:multipart/form-data; boundary="; szContentType += szBoundary; pHttpFile->AddRequestHeaders(szContentType.GetBuffer(0)); /*打开文件,合成文件头部数据,取出文件数据,以及合成尾部数据,计算总长度*/ struct DataInfo{ char* pBuf; DWORD BufLen; DataInfo(){ ZeroMemory(this, sizeof(DataInfo)); } }; std::vector<DataInfo> DataInfoList; wstring strAccount = L"test@163.com"; wstring strMsg = L"崩溃了"; CString FileName = file.GetFileName(); char key1[1024] = { 0 }; sprintf(key1, " ------------------------------096304854221961038114493 " "Content-Disposition: form-data;name="Account" %s", UnicodeToUtf8(strAccount).c_str());//如果value有中文必须转成UTF-8 char key2[1024] = { 0 }; sprintf(key2, " ------------------------------096304854221961038114493 " "Content-Disposition: form-data;name="Message" %s", UnicodeToUtf8(strMsg).c_str());//如果value有中文必须转成UTF-8 char strFileconnet[1024]= { 0 }; sprintf(strFileconnet, " ------------------------------096304854221961038114493 " "Content-Disposition:form-data;name="file";filename="%s.zip" " "Content-Type:application/zip ", UnicodeToUtf8(FileName).c_str()); //拼body string strconnet = key1; strconnet += key2; strconnet += strFileconnet; DWORD dwTotalBodyLen = 0; //每个文件的头部信息 DataInfo preDi; preDi.BufLen = strlen(strconnet.c_str()); preDi.pBuf = new char[preDi.BufLen]; memcpy(preDi.pBuf, strconnet.c_str(), preDi.BufLen); DataInfoList.push_back(preDi); dwTotalBodyLen += preDi.BufLen; //文件内容 DataInfo ContDi; ContDi.BufLen = (DWORD)file.GetLength(); ContDi.pBuf = new char[ContDi.BufLen]; file.Read(ContDi.pBuf, ContDi.BufLen); DataInfoList.push_back(ContDi); file.Close(); dwTotalBodyLen += ContDi.BufLen; //尾长度 const char* szEndContent = " " "------------------------------096304854221961038114493-- "; DataInfo EndDi; EndDi.BufLen = strlen(szEndContent); EndDi.pBuf = new char[EndDi.BufLen]; memcpy(EndDi.pBuf, szEndContent, EndDi.BufLen); DataInfoList.push_back(EndDi); dwTotalBodyLen += EndDi.BufLen; /*发送数据*/ pHttpFile->SendRequestEx(dwTotalBodyLen, HSR_SYNC | HSR_INITIATE); std::vector<DataInfo>::iterator it3 = DataInfoList.begin(); for (; it3 != DataInfoList.end(); it3++) { pHttpFile->Write(it3->pBuf, it3->BufLen); delete[]it3->pBuf; } pHttpFile->EndRequest(HSR_SYNC); /*获取状态*/ char* RetStr = NULL; DWORD dwStatusCode = -1; pHttpFile->QueryInfoStatusCode(dwStatusCode); if (dwStatusCode == HTTP_STATUS_OK) { //读返回 RetStr = new char[(DWORD)pHttpFile->GetLength()]; pHttpFile->Read(RetStr, (UINT)pHttpFile->GetLength()); if (pHttpFile) delete pHttpFile; if (pHttpConnection) delete pHttpConnection; session.Close(); ::PostMessage(this->GetSafeHwnd(), WM_EXIT_BUGREPORT, 0, 0);//完成退出BugReport return TRUE; } else { if (pHttpFile != NULL) { pHttpFile->Close(); delete pHttpFile; pHttpFile = NULL; } if (pHttpConnection != NULL) { pHttpConnection->Close(); delete pHttpConnection; pHttpConnection = NULL; } session.Close(); CString errText; errText.Format(L"POST出错,错误码:%d", dwStatusCode); theLogger.TraceError(errText); ::PostMessage(this->GetSafeHwnd(), WM_EXIT_BUGREPORT, 0, 0);//完成退出BugReport return FALSE; } } } } } catch (...) { if (pHttpFile != NULL) { pHttpFile->Close(); delete pHttpFile; pHttpFile = NULL; } if (pHttpConnection != NULL) { pHttpConnection->Close(); delete pHttpConnection; pHttpConnection = NULL; } session.Close(); DWORD dwError = GetLastError(); CString str; str.Format(L"Unknow Exception occur %d", dwError); theLogger.TraceError(str); ::PostMessage(this->GetSafeHwnd(), WM_EXIT_BUGREPORT, 0, 0);//完成退出BugReport return FALSE; } if (pHttpFile != NULL) pHttpFile->Close(); if (pHttpConnection != NULL) pHttpConnection->Close(); session.Close(); ::PostMessage(this->GetSafeHwnd(), WM_EXIT_BUGREPORT, 0, 0);//完成退出BugReport return TRUE; } int main() { wstring url = L"http://localhost:8080"; wstring strFilepath; //获取工作路径 TCHAR szModulePath[MAX_PATH * 2] = { 0 }; ::GetModuleFileName(NULL, szModulePath, _countof(szModulePath) - 2); PathRemoveFileSpec(szModulePath); strFilepath = szModulePath; strFilepath += L"\测试.zip"; PostUploadFile(url.c_str(), strFilepath .c_str()); return 0; }

     点击下载:MFC上传文件demo

  • 相关阅读:
    开发一个App的成本是多少?
    自定义Drawable
    数据库服务软件类型和配置redis
    分库分表
    创建视图
    部署MYSQL高可用集群
    读写分离《二》
    读写分离和多实例
    部署mysql主从同步
    备份和恢复
  • 原文地址:https://www.cnblogs.com/chechen/p/10123293.html
Copyright © 2011-2022 走看看