MFC发送HTTP请求

1 MFC 处理 HTTP 请求的基本方法

1.1 配置本地的 HTTP 服务器

为方便测试,可以先配置一个本地的 HTTP 服务器,根据各种需要进行定制。

我在这里,用 JSP 定制了一个基本的 HTML 表单程序,分为 index.jsp 和 RequestObjectInJSP.jsp 两个文件。其中,index.jsp 用来提供表单程序,方便测试 RequestObjectInJSP.jsp 这个表单处理文件。

为了减少在测试时期网络通信的影响,强烈建议搭建一个本地的 Web 服务器。

1.2 MFC 发起 HTTP 请求的基本方法

用 CInternetSession 来发起 Http 请求,需要包含头文件:

#include <afxinet.h>

MFC 发起 HTTP 请求的逻辑,和用 WinINet 函数集 的整体过程类似,主要的步骤在 Steps in a Typical HTTP Client Application 有详细的描述。

Retrieving a file via. HTTP 一文也对 MFC 发起 HTTP 请求有着非常详细的介绍。

1.3 用 MFC 发起 HTTP GET 请求

Get 服务类别,估计是 HTML 里最常用的,平时浏览网页用的就是这种。下面是用 GET 的方法来请求某个网页的内容,代码如下:

//通过 http GET 协议来获取并保存文件
CInternetSession session;
session.SetOption(INTERNET_OPTION_CONNECT_TIMEOUT, 1000 * 20);
session.SetOption(INTERNET_OPTION_CONNECT_BACKOFF, 1000);
session.SetOption(INTERNET_OPTION_CONNECT_RETRIES, 1);

CHttpConnection* pConnection = session.GetHttpConnection(TEXT("localhost"),(INTERNET_PORT)8080);
CHttpFile* pFile = pConnection->OpenRequest( CHttpConnection::HTTP_VERB_GET,
                                             TEXT("/Practice/index.jsp"));

CString szHeaders = L"Accept: audio/x-aiff, audio/basic, audio/midi,\
                     audio/mpeg, audio/wav, image/jpeg, image/gif, image/jpg, image/png,\
                     image/mng, image/bmp, text/plain, text/html, text/htm\r\n";

pFile->AddRequestHeaders(szHeaders);

pFile->SendRequest();

DWORD dwRet;
pFile->QueryInfoStatusCode(dwRet);

if(dwRet != HTTP_STATUS_OK)
{
    CString errText;
    errText.Format(L"POST出错,错误码:%d", dwRet);
    AfxMessageBox(errText);
}
else
{
    int len = pFile->GetLength();
    char buf[2000];
    int numread;
    CString filepath;
    CString strFile = L"response.txt";
    filepath.Format(L".\\%s", strFile);
    CFile myfile( filepath,
                  CFile::modeCreate|CFile::modeWrite|CFile::typeBinary);
    while ((numread = pFile->Read(buf,sizeof(buf)-1)) > 0)
    {
        buf[numread] = '\0';
        strFile += buf;
        myfile.Write(buf, numread);
    }
    myfile.Close();
}

session.Close();
pFile->Close(); 
delete pFile;

调试上面这段代码的时候,特别要注意以下几点:

  1. CHttpConnection::GetHttpConnection() 里第一参数,填写的应该是类似 www.yahoo.com 这样的根域名,如果带上 http:// 或是子路径,好像均会出错。
  2. CHttpFile::OpenRequest() 的第一个和第二个参数很重要,会影响是否能连接,尤其是第二个参数,要输入正确的 URI 路径;
  3. 在 CHttpFile::SendRequest() 之后,一定要用 CHttpFile::QueryInfoStatusCode() 来获得请求的状态码,从而判断是否正确获得了 http 数据;

    Http 的状态码主要有以下几类:

    Group     Meaning
    200-299   Success
    300-399   Information
    400-499   Request error
    500-599   Server error
    

    更详细的代码参数:

    Status code         Meaning
      200           URL located, transmission follows
      400           Unintelligible request
      404           Requested URL not found
      405           Server does not support requested method
      500           Unknown server error
      503           Server capacity reached
    

1.4 用 MFC 发起 HTTP Post 请求

用 MFC 发起 HTTP Post 请求,主要流程和 MFC HTTP Get 代码一样,以下是示例代码:

//通过 http POST 协议来发送命令给服务器
CInternetSession session;
session.SetOption(INTERNET_OPTION_CONNECT_TIMEOUT, 1000 * 20);
session.SetOption(INTERNET_OPTION_CONNECT_BACKOFF, 1000);
session.SetOption(INTERNET_OPTION_CONNECT_RETRIES, 1);

CHttpConnection* pConnection = session.GetHttpConnection( TEXT("localhost"),
                                                          (INTERNET_PORT)8080);
CHttpFile* pFile = pConnection->OpenRequest( CHttpConnection::HTTP_VERB_POST,
                                             TEXT("/Practice/RequestObjectInJSP.jsp"),
                                             NULL,
                                             1,
                                             NULL,
                                             TEXT("HTTP/1.1"),
                                             INTERNET_FLAG_RELOAD);

//需要提交的数据
CString szHeaders   = L"Content-Type: application/x-www-form-urlencoded;";

//下面这段编码,则是可以让服务器正常处理
CHAR* strFormData = "username=WaterLin&password=TestPost";
pFile->SendRequest( szHeaders,
                    szHeaders.GetLength(),
                    (LPVOID)strFormData,
                    strlen(strFormData));

DWORD dwRet;
pFile->QueryInfoStatusCode(dwRet);

if(dwRet != HTTP_STATUS_OK)
{
    CString errText;
    errText.Format(L"POST出错,错误码:%d", dwRet);
    AfxMessageBox(errText);
}
else
{
    int len = pFile->GetLength();
    char buf[2000];
    int numread;
    CString filepath;
    CString strFile = L"result.html";
    filepath.Format(L".\\%s", strFile);
    CFile myfile(filepath,
        CFile::modeCreate|CFile::modeWrite|CFile::typeBinary);
    while ((numread = pFile->Read(buf,sizeof(buf)-1)) > 0)
    {
        buf[numread] = '\0';
        strFile += buf;
        myfile.Write(buf, numread);
    }
    myfile.Close();
}

session.Close();
pFile->Close(); 
delete pFile;

以上的代码,与 Get 对比起来,唯一的不同在于,提交 CHttpFile::SendRequest() 数据的时候,把表单的数据也带上了。

2 疑难杂症

2.1 字符编码,可恨的字符编码

对于 C/C++ 程序来说,最可恨的事情之一,莫过于字符集的问题了,尤其是在网络通信的时候,这一问题就显得更加让人恶心了。

如果在用 MFC 发起 HTTP Post 请求时,你用的是宽字符集的编码,比如说,我把用 MFC 发起 HTTP Post 请求里同样的几行代码,替换成下面这几句:

CString szHeaders   = L"Content-Type: application/x-www-form-urlencoded;charset=UTF-8";

//下面这句,因为字符集的原因,是无法让服务器正常处理
CString strFormData = L"username=WaterLin&password=TestPost";
pFile->SendRequest( szHeaders,
                    szHeaders.GetLength(),
                    (LPVOID)(LPCTSTR)strFormData,
                    lstrlen(strFormData));

如果是,在服务器端会解析为如下这样:

<br>Parameters:u s e r n a m e

当你用文本编辑器打开返回的文件时,会显示如下的错误提示:

./images/CopyError-waterlin.png

这个时候,虽然上面的 JSP 代码会输出

Character Encoding: null 

这样的值,但是服务器却会把表单内容当成 ISO-8859-1 字符集来处理,从而把表单参数解析为类似下面的怪胎:

看,这就是把字符集弄混了的下场!

则需要在 HTTP 报头里,一定要显式加上 charset=UTF-8 这样的约束,比如,在上面的代码,我就是直接这样写的:

CString szHeaders   = L"Content-Type: application/x-www-form-urlencoded;charset=UTF-8";

这样,服务器在收到你的报文时,就知道,你的 Form 表单内容,是用 UTF-8 来编码的,它也会用 UTF-8 字符集来解码你的 request,从而保证收到的消息一样。



### 回答1: MFC发送POST请求JSON数据,可以通过以下步骤实现: 1. 设置请求头 首先需要设置请求头,包括Content-Type和Content-Length。Content-Type设置为application/json,Content-Length设置为JSON数据的长度。 2. 创建JSON字符串 创建一个JSON字符串,可以使用CJsonObject等库来构造JSON字符串。 3. 创建连接对象 创建连接对象,使用CInternetSession::GetHttpConnection方法建立连接。 4. 发送请求 使用CHttpFile::SendRequest方法发送POST请求,并将JSON字符串作为请求内容发送出去。 5. 接收响应 使用CHttpFile::QueryInfoStatusCode获取HTTP状态码,判断请求是否成功。如果成功,使用CHttpFile::ReadString方法读取响应内容。 6. 关闭连接 使用CHttpFile::Close方法关闭连接。 以上就是MFC发送POST请求JSON数据的步骤。需要注意的是,在使用MFC发送POST请求时,需要在请求字符串中添加转义字符,以确保JSON数据能够正确传输。在发送请求前,可以通过调试工具查看请求内容,以帮助排查请求发送过程中的问题。 ### 回答2: MFC是微软的一套资源库,包含了许多封装好的类和模块,能够方便地开发Windows应用程序。而json是一种轻量级的数据交换格式,经常用于Web服务之间的数据传输。在MFC中使用Post请求发送json数据也是很常见的一种操作。 发送Post请求的方式有很多种,MFC中可以使用CInternetSession和CHttpConnection等类进行实现。首先,需要创建一个Internet会话对象,并通过该对象建立一个HTTP连接。在建立HTTP连接时,需要设置服务地址和端口号等参数。然后,可以构造一个HTTP请求,指定请求类型为POST,并将json数据填充到请求正文中。最后,通过连接对象的SendRequest方法,将HTTP请求发送给Web服务端,等待服务端响应。 具体实现可以按照以下步骤进行: 1.引入相关头文件: #include <afxinet.h> #include <afxdisp.h> #include <afxwin.h> #include <afx.h> 2.创建Internet会话对象: CInternetSession* pSession = new CInternetSession(); 3.连接Web服务: CHttpConnection * pConnect = pSession->GetHttpConnection(L"www.example.com",INTERNET_DEFAULT_HTTP_PORT,NULL,NULL); 4.构造HTTP请求: CString strUrl = L"/api/data"; CHttpFile* pFile = pConnect->OpenRequest(CHttpConnection::HTTP_VERB_POST,strUrl); 5.设置请求头信息: pFile->AddRequestHeaders(L"Content-Type: application/json"); 6.构造json数据: CString strJsonData = L"{\"key\":\"value\"}"; 7.设置请求正文: pFile->SendRequestEx(strJsonData,len,strPostData.GetLength()); 8.等待服务端响应: CString strResponse; pFile->ReadString(strResponse); 9.关闭连接: pFile->Close(); delete pConnect; delete pFile; 10.释放会话对象: delete pSession; 以上就是在MFC发送Post请求json数据的方法。在实际开发中,还需要根据具体情况进行调整和优化。 ### 回答3: MFC(Microsoft Foundation Class)是微软公司开发的一组类库,用于在Windows操作系统上开发图形用户界面程序。MFC常用于开发Windows桌面应用程序,它提供了一套面向对象的框架,让开发过程更加高效、方便。 在MFC发送POST请求并传输JSON数据可以通过以下步骤实现: 1. 首先,需要使用CInternetSession对象建立一个Internet会话。 ``` CInternetSession session(_T("MySession")); ``` 2. 接着,需要通过CInternetSession对象创建一个HttpConnect连接并指定服务器信息和端口号。 ``` CHttpConnection* pHttpConnect = session.GetHttpConnection(_T("localhost"), INTERNET_DEFAULT_HTTP_PORT); ``` 3. 创建一个HttpPost请求并设置请求头和请求体,请求体可以使用JSON格式进行传输。 ``` CString strRequest = _T("name=John&age=20"); CString strHeaders = _T("Content-Type: application/json\r\n"); CHttpFile* pHttpFile = pHttpConnect->OpenRequest(CHttpConnection::HTTP_VERB_POST, _T("/api/example"), nullptr, 1, nullptr, nullptr, INTERNET_FLAG_RELOAD); pHttpFile->AddRequestHeaders(strHeaders); pHttpFile->SendRequest(strRequest, strRequest.GetLength()); ``` 4. 发送HttpPost请求,并获取服务器返回的响应结果。 ``` CString strResponse; DWORD dwBytesRead = 0; CHAR buff[1024] = { 0 }; while (dwBytesRead = pHttpFile->Read(buff, 1024)) { strResponse += buff; } pHttpFile->Close(); pHttpConnect->Close(); session.Close(); ``` 通过以上方法可以完成在MFC发送POST请求并传输JSON数据的操作。需要注意的是,请求头中需要设置Content-Type为application/json,同时请求体中的数据必须是JSON格式的字符串。此外,还需要注意HttpConnect连接、HttpPost请求和HttpFile对象的生命周期问题,确保在使用后及时进行关闭和销毁。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值