我是靠谱客的博主 怕孤单凉面,最近开发中收集的这篇文章主要介绍HTTP 文件上传的几种方式(WinInet、winhttp、curl)小结,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

通过HTTP实现文件上传,有三种方式,分别是:WinInet、WinHttp、CURL模拟表单上传文件。

 

一、WinInet版本:

#include "stdafx.h"
#include <stdio.h>
#include <windows.h>
#include <winsock2.h>
#include <wininet.h>
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "wininet.lib")

namespace
{
	LPCTSTR boundary = TEXT("-----------------------------1234567890123"); //随机字符串
	LPCSTR aboundary = "-----------------------------1234567890123";
}
//
BOOL DoUploadFile(char *pszFilePath, char *pszFileName)
{
	HINTERNET hSession = InternetOpen("HttpSendRequest",
		INTERNET_OPEN_TYPE_PRECONFIG,
		NULL,
		NULL,
		0); //同步方式


	if(!hSession)
	{
		printf("Failed to open InternetOpenn");
		return -1;
	}

	//连接到一个http服务:
	HINTERNET hConnect = InternetConnect(hSession,
		"127.0.0.1",
		8899/*INTERNET_DEFAULT_HTTP_PORT*/, //连接到80端口
		NULL,
		NULL,
		INTERNET_SERVICE_HTTP, //服务类型HTTP,FTP或Gopher
		0,
		1);

	if(!hConnect)
	{
		printf("error InternetConnectn");
		return -1;
	}

	//上传文件
	HINTERNET hRequest = HttpOpenRequest(hConnect, 
		"POST",
		"/CRMFiles/"/*远程文件夹名字*/, 
		HTTP_VERSION/*NULL*/, 
		NULL, 
		NULL, 
		INTERNET_FLAG_KEEP_CONNECTION/*INTERNET_FLAG_NO_CACHE_WRITE*/, 
		0);

	if (!hRequest)
	{
		printf("Failed to open request handle: %lun", GetLastError ());
		return FALSE;
	}

	//打开指定的文件:
	HANDLE hFile = CreateFile(pszFilePath, 
		GENERIC_READ, 
		FILE_SHARE_READ|FILE_SHARE_WRITE,
		NULL, 
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL,
		NULL);

	if (hFile == INVALID_HANDLE_VALUE)
	{
		printf("nFailed to open local file %s.", pszFilePath);
		return FALSE;
	}
	DWORD dwFileSize = GetFileSize(hFile, 0);
	printf ("File size is %dn", dwFileSize );


    TCHAR content_type[128] = {0};
    _stprintf_s(content_type, TEXT("Content-Type: multipart/form-data; boundary=%s"), boundary);
    
	LPTSTR referer = TEXT("Referer: http://127.0.0.1/CRMFiles");
    LPTSTR accept = TEXT("Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
    LPTSTR accept_lan = TEXT("Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3");
    LPTSTR accept_encoding = TEXT("Accept-Encoding: gzip, deflate");
    LPTSTR user_agent = TEXT("User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:22.0) Gecko/20100101 Firefox/22.0");

	HttpAddRequestHeaders(hRequest, content_type, -1, HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE);
	HttpAddRequestHeaders(hRequest, referer, -1, HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE);
	HttpAddRequestHeaders(hRequest, accept, -1, HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE);
	HttpAddRequestHeaders(hRequest, accept_lan, -1, HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE);
	HttpAddRequestHeaders(hRequest, accept_encoding, -1, HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE);

	char first_boundary[128] = {0};
	char delimiter[128] = {0};
	char end_boundary[128] = {0};
	sprintf_s(first_boundary, "--%srn", aboundary);
	sprintf_s(delimiter, "rn--%srn", aboundary);
	sprintf_s(end_boundary, "rn--%s--rn", aboundary);

	char content_dispos[128] = {0};
	if (strlen(pszFileName) > 0){
		_stprintf_s(content_dispos, "Content-Disposition: form-data; name="fileupload"; filename="%s"rn", pszFileName);
	} 
	//LPSTR content_dispos = "Content-Disposition: form-data; name="fileupload"; filename="123.jpg"rn";    
	LPSTR content_type2 = "Content-Type: application/octet-streamrnrn";
	LPSTR rn = "rn";

	//
	INTERNET_BUFFERS BufferIn = {0};
	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 = dwFileSize
		+strlen(first_boundary)
		+strlen(content_dispos)
		+strlen(content_type2)
		+strlen(end_boundary); //Content-Length:
	BufferIn.dwOffsetLow = 0;
	BufferIn.dwOffsetHigh = 0;

	if(!HttpSendRequestEx( hRequest, &BufferIn, NULL, 0/*HSR_INITIATE*/, 0))
	{
		InternetCloseHandle(hRequest);
		InternetCloseHandle(hConnect);
		InternetCloseHandle(hSession);
		printf( "Error on HttpSendRequestEx %lun", GetLastError() );
		return FALSE;
	}


	DWORD dwWrittenBytes = 0;
	InternetWriteFile(hRequest, (byte*)first_boundary, strlen(first_boundary), &dwWrittenBytes); //first boundary
	InternetWriteFile(hRequest, (byte*)content_dispos, strlen(content_dispos), &dwWrittenBytes);
	InternetWriteFile(hRequest, (byte*)content_type2, strlen(content_type2), &dwWrittenBytes);

	//BYTE *lpBuffer = (BYTE*)VirtualAlloc(0, dwFileSize, MEM_COMMIT, PAGE_READWRITE);
	DWORD sum = 0;
	DWORD dwBytesRead = 0;
	DWORD dwBytesWritten = 0;
	BYTE pBuffer[5120] = {0}; // 按照5kb读取文件(栈的大小为1M,超过1M将提示溢出)
	BOOL bRead, bRet;

	do
	{
		if (!(bRead = ReadFile (hFile, pBuffer, sizeof(pBuffer), &dwBytesRead, NULL)))
		{
			printf ("nReadFile failed on buffer %lu.",GetLastError());
			break;
		}
		if (!(bRet=InternetWriteFile( hRequest, pBuffer, dwBytesRead, &dwBytesWritten)))
		{
			printf ("nInternetWriteFile failed %lu", GetLastError()); 
			break;
		}
		sum += dwBytesWritten;
	}while (dwBytesRead == sizeof(pBuffer));
	//
	CloseHandle(hFile);
	
	//last boundary
	InternetWriteFile(hRequest, (byte*)end_boundary, strlen(end_boundary), &dwWrittenBytes);

	printf ("Actual written bytes: %dnupload %s successed!n", sum, pszFileName);
	
	//结束一个HTTP请求:
	if(!HttpEndRequest(hRequest, NULL, 0, 0))
	{
		printf( "Error on HttpEndRequest %lu n", GetLastError());
		return FALSE;
	}
	InternetCloseHandle(hRequest);
	InternetCloseHandle(hConnect);
	InternetCloseHandle(hSession);

	//VirtualFree(lpBuffer, 0, MEM_RELEASE);

	return TRUE;
}

//
int main(int argc, char **argv)
{
	BOOL bOkey = DoUploadFile("d:\test.jpg", "test123.jpg");
	if(!bOkey)
	{
		printf("error DoUploadFilen");
	}
	system("pause");

	return 0;
}

二、winhttp版本

待发布~~~~

 

三、libcurl版本

通过模拟表单上传文件到服务端,代码部分:

#include "stdafx.h"
#include <iostream>
#include <string.h>
#include <assert.h>
#include "curl.h"
using namespace std;

/**
 * @brief 回调函数,得到响应内容
 */
int write_data(void* buffer, int size, int nmemb, void* userp)
{
	std::string * str = dynamic_cast<std::string *>((std::string *)userp);
	str->append((char *)buffer, size * nmemb);
	return nmemb;
}

/**
 * @brief upload
 */
bool upload(string url, string filePath, string fileName, string &response, long &statusCode)
{
	CURL *curl = curl_easy_init();
	struct curl_httppost* post = NULL;
	struct curl_httppost* last = NULL;

	if (curl)
	{
		//指定url
		curl_easy_setopt(curl, CURLOPT_URL, (char *)url.c_str());

		/* Fill in the file upload field */
		/*curl_formadd(&post,
			&last,
			CURLFORM_COPYNAME, "file",
			CURLFORM_FILE, "d:\beyond.mp3",
			CURLFORM_END);*/

		CURLFORMcode formCode = CURL_FORMADD_OK;
		formCode = curl_formadd(&post,
			&last,
			CURLFORM_PTRNAME, "file",
			CURLFORM_FILE, (char*)filePath.c_str(),
			CURLFORM_FILENAME, (char*)fileName.c_str(),
			CURLFORM_END);// form-data key(file) "filePath"为文件路径,"fileName"为文件上传时文件名

		/* Fill in the filename field */
		/*curl_formadd(&post,
			&last,
			CURLFORM_COPYNAME, "name",
			CURLFORM_COPYCONTENTS, "EasyCurl.h",
			CURLFORM_END);*/

		/* Fill in the submit field too, even if this is rarely needed */
		curl_formadd(&post,
			&last,
			CURLFORM_COPYNAME, "submit",
			CURLFORM_COPYCONTENTS, "submit",
			CURLFORM_END);

		//构造post参数
		curl_easy_setopt(curl, CURLOPT_HTTPPOST, post);
		//绑定相应
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
		//绑定响应内容的地址
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)(&response));
		//支持重定向(HFS作为文件服务端,不加这句代码,状态码返回的是301)
		curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
		//执行请求
		CURLcode ret = curl_easy_perform(curl);
		//获取返回信息
		curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &statusCode);
		//
		curl_easy_cleanup(curl);

		return (ret == CURLE_OK);
	} 
	else
	{ 
		return false;
	}
}

//
int _tmain(int argc, _TCHAR* argv[])
{
	std::string response;
	long statuscode = 0;
	int code = upload("http://127.0.0.1:7879/CRMFiles", "d:\error.wav", "_123.mp3", response, statuscode);

	cout << "code : "<< code << endl;
	cout << "status_code : "<< statuscode << endl;
	cout << "response : "<< response.c_str() << endl;

	getchar();

	return 0;
}

关于分片上传(multipart/form-data)的一些资料:

https://blog.csdn.net/qq_29214249/article/details/78363220

https://blog.csdn.net/qq_33706382/article/details/78168325

 

tips:搭建服务端可以使用hfs,很好用的一款免费软件!

最后

以上就是怕孤单凉面为你收集整理的HTTP 文件上传的几种方式(WinInet、winhttp、curl)小结的全部内容,希望文章能够帮你解决HTTP 文件上传的几种方式(WinInet、winhttp、curl)小结所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(60)

评论列表共有 0 条评论

立即
投稿
返回
顶部