文号
t71986
阅读
6671
回复
1
收藏
2
MFC进行HTTP访问
2015/06/12
IP:四川
要进行HTTP访问,需要在stdafx.h包含#include <afxinet.h>,引入三个类:CInternetSession、CHttpConnection、CHttpFile。
CInternetSession用于打开网络连接(GetHttpConnection),CHttpConnection用以维持网络连接并打开请求(OpenRequest),CHttpFile用以发送请求(SendRequest)。

首先要考虑编码问题——网络上应用最广的是UTF-8编码,而Windows和MFC则是UTF-16编码。MFC访问HTTP获得的可能是UTF-8或GBK,然而MFC的程序内码却可能是UTF-16(这种编码基本不可能出现在Internet),内置的网络访问类并不会自动转码,直接当作CString接收有可能会导致乱码。因此需要写一个转码函数(这个转码函数在ANSI编译时也能正常工作):
CString mbcs2tcs(CStringA astr, bool isutf8)
{
    if (isutf8) {
        int length = MultiByteToWideChar(CP_UTF8, 0, astr, -1, NULL, 0);
        wchar_t *bufnew = new wchar_t[length + 1];
        MultiByteToWideChar(CP_UTF8, 0, astr, -1, bufnew, length);
        bufnew[length] = 0;
        CString wstr(bufnew);
        delete []bufnew;
        return wstr;
    }
    else {
        return (CString) astr;
    }
}
 
CStringA tcs2mbcs(CString str, bool isutf8)
{
    if (isutf8) {
        CStringW wstr = (CStringW) str;
        int length = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
        char *bufnew = new char[length + 1];
        WideCharToMultiByte(CP_UTF8, 0, wstr, -1, bufnew, length, NULL, NULL);
        bufnew[length] = 0;
        CStringA astr(bufnew);
        delete []bufnew;
        return astr;
    }
    else {
        return (CStringA) str;
    }
}

其中用处最广的GET有一个捷径,先建立一个CInternetSession对象,然后用它打开任意的URL(OpenURL)即可返回一个CStdioFile对象(可附带请求头部),通常会是CHttpFile。调用Read()即可获得返回的内容,然后转码显示即可。
void CHttpTestDlg::OnBnClickedRunRequest()
{
    UpdateData(true);
             
    try {
        CInternetSession inetsess; // CInternetSession
        CHttpFile *file = NULL;
             
        file = (CHttpFile*)
                inetsess.OpenURL(m_url, 1, INTERNET_FLAG_TRANSFER_ASCII | INTERNET_FLAG_RELOAD,
                                               m_reqheader, _tcslen(m_reqheader));
             
                     
        m_recv = _T(""); // 清空文本框
                     
        char buf[1024] = {0};
        int ncount;
        CStringA ansistr;
             
        while (ncount = file->Read(buf, 1023)) {
            buf[ncount] = '\0';
            ansistr += buf;
        }
                     
        m_recv = mbcs2tcs(ansistr, m_isutf8); // 从GB2312转码到wchar_t(如果是ANSI编译则不转码)输出到文本框
                 
        file->Close(); // 关闭请求文件
                         
        if (file != NULL) 
            delete file;
             
        inetsess.Close(); // 关闭CInternetSession
    }
    catch (CException &e) {
        m_recv = _T("获取错误");
    }
    UpdateData(false);
             
}
运行截图:
捕获ttt.png
捕获ttu.png

要进行POST访问,就要采用逐步的方法了,首先解析输入的URL(AfxParseURL),分出服务器、路径、端口等信息,然后打开HTTP连接(GetHttpConnection),获得CHttpConnection,再从连接打开请求(OpenRequest)向服务器请求路径,获得CHttpFile,然后发送(SendRequest)请求头部和POSTDATA,最后Read()数据,转码显示即可。因为各种原因,POSTDATA也一定要是UTF-8或GBK的,不能是UTF-16。
void CHttpTestDlg::OnBnClickedPostCmd()
{
    UpdateData(true);
             
    try {
        CInternetSession inetsess; // CInternetSession
        CHttpConnection *connect = NULL;
        CHttpFile *file = NULL;
             
        { // POST请求:通过CInternetSession打开HTTP连接,然后再用HTTP连接打开HTTP请求,发送请求
                         
            DWORD svctype;
            CString srvname;
            CString objname;
            INTERNET_PORT port;
             
            AfxParseURL(m_url, svctype, srvname, objname, port); // 解析URL,得到服务器名、路径名、端口名等
             
            connect = inetsess.GetHttpConnection(srvname, port); // 建立HTTP连接,到服务器和端口
             
            file = connect->OpenRequest(_T("POST"), objname); // 打开HTTP请求,类型POST,到路径名
             
            // 发送请求,附带头部和附加信息。附加数据必须为ANSI或UTF-8,要进行转换
            CStringA postdata = tcs2mbcs(m_postdata, m_isutf8);
            LPCSTR postbuffer = (LPCSTR)postdata;
            file->SendRequest(m_reqheader, m_reqheader.GetLength(), (LPVOID)postbuffer, strlen(postbuffer));
        }
             
        m_recv = _T(""); // 清空文本框
                     
        char buf[1024] = {0};
        int ncount;
        CStringA ansistr;
             
        while (ncount = file->Read(buf, 1023)) {
            buf[ncount] = '\0';
            ansistr += buf;
        }
                     
        m_recv = mbcs2tcs(ansistr, m_isutf8); // 从GB2312转码到wchar_t(如果是ANSI编译则不转码)输出到文本框
                     
        file->Close();
        connect->Close();
        if (file != NULL) // 关闭请求文件
            delete file;
        if (connect != NULL) // 关闭连接
            delete connect;
        inetsess.Close(); // 关闭CInternetSession
    }
    catch (CException &e) {
        m_recv = _T("获取错误");
    }
    UpdateData(false);
}
运行截图:
捕获ttv.png
attachment icon HttpTest.rar 1.09MB RAR 108次下载
[ 修改于11年6个月前 - 2015/06/12 09:50:36 ]
笔记
{{note.content}}
{{n.user.username}}
{{fromNow(n.toc)}} {{n.status === noteStatus.disabled ? "已屏蔽" : ""}} {{n.status === noteStatus.unknown ? "正在审核" : ""}} {{n.status === noteStatus.deleted ? '已删除' : ''}}
  • 编辑
  • 删除
  • {{n.status === 'disabled' ? "解除屏蔽" : "屏蔽" }}
我也是有底线的