zoukankan      html  css  js  c++  java
  • 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
    ";
    
    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] = '';
            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] = '';
            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,从而保证收到的消息一样。

  • 相关阅读:
    子类调用父类被重写的方法
    Linux下编译出现undefined reference to ‘pthread_create’问题解决
    CRC校验8
    嵌入式C语言查表法
    Static关键字,遇到的问题_1
    java中方法的参数传递机制_一个对象被当作参数传递到一个方法后
    String使用equals和==比较的区别
    如何导入XML数据 (python3.6.6区别于python2 环境)
    0xx_PHP核心01
    PHP_MVC设计模式02
  • 原文地址:https://www.cnblogs.com/thbCode/p/4365461.html
Copyright © 2011-2022 走看看