65.9K
CodeProject 正在变化。 阅读更多。
Home

探索 ISAPI。处理 GET-POST 数据

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.67/5 (5投票s)

2002年7月14日

4分钟阅读

viewsIcon

107105

downloadIcon

2525

本文介绍了一种从表单中检索 GET-POST 数据到 ISAPI 扩展的方法。

Sample Image

引言

本文介绍了一种从 ISAPI 扩展中的表单检索 GET-POST 数据的方法。还提供了两个有用的参数集合类。由于非 MFC ISAPI 扩展在速度和同时连接数方面更可靠,因此包含了一个非 MFC 版本。

功能

MFC 和非 MFC 版本都使用基于 STL 的 Vector、Map 和 String 类,其中包含非 MFC 代码。在 MFC 版本中,string 集合基于 _bstr_t 类型。在非 MFC 版本中,string 集合基于 STL String 类型。因此,MFC 版本使用基于 ISAPI MFC 的宏来检索服务器变量和参数数据,而非 MFC 版本使用 WriteClient 和 ServerSupportFunction HTTP 函数。

默认方法会向浏览器写入一个复杂的表单,其中包含复选框、编辑框、单选按钮、文本区域——甚至还有文件类型的编辑框。其思想是将所有 POST 参数接收到同一个 DLL 扩展中。该表单使用 LoadLongResource 辅助函数从 HTML string 资源加载。这减少了构建页面的时间,因为 string 在扩展第一次调用时加载到内存中。在我的 《从 ISAPI 访问 ADO 数据》 文章中展示了如何在 Visual Studio 项目中使用 HTML string 资源。

GET 数据非常容易接收,因为这种数据是通过 URL 从浏览器发送到服务器的。POST 数据变量对用户是透明的,并且可以传输大量数据。有关 GET/POST 数据的更多信息,请参阅我的 《HTTP GET-POST 工具》 文章。

MFC 版本

用于存储数据集合中参数的 C++ 类是 Twin 和 TwinVector。ISAPI MFC 版本的 Default 方法将 IDR_HTML_FORM 资源写入客户端浏览器。FormRequest 是在单击“Submit Query”按钮后接收控制的方法。

void CPostDataExtension::FormRequest(CHttpServerContext* pCtxt, 
                                     void* pVoid, DWORD dwBytes)
{                                
    //build the STL collection from server variables and POST data 
    TwinVector    vecServerCtx(pCtxt, (LPTSTR)pVoid);    

    //write on browser stream the server context variables
    WriteServerData(pCtxt);            

    //write on browser stream the STL collection of 
    //server context variables and POST data
    WriteServerVar(pCtxt, vecServerCtx);    
}

一个小问题是如何在 DLL 入口点获取控制到 FormRequest 方法。在 MFC 中,这非常容易实现,使用宏。

DEFAULT_PARSE_COMMAND(FormRequest,    CPostDataExtension)
ON_PARSE_COMMAND(FormRequest,        CPostDataExtension, ITS_RAW)

为了正确知道哪个方法将接收 POST 数据,MFC 包装器必须从 HTML 表单接收一个隐藏参数,该参数必须位于 FORM HTML 标签之后的第一位。

<form action="PostData.dll?" method=post>
<input TYPE=hidden NAME="MfcISAPICommand" VALUE="FormRequest">

在 WriteServerVar 辅助函数中,服务器上下文变量集合被写入 HTTP 流。可以直接获取所需参数的值:

bstrValue = vecServerCtx.Find(L"Filename").
for (itVec = vecServerCtx.begin(); itVec != vecServerCtx.end(); itVec++)
    *pCtxt    <<    <itvec->GetName()    << " = " <<<itvec->    GetValue()    << "br";
</itvec-></itvec->

Sample Image

在同一个 WriteServerVar 辅助函数中,POST 数据集合以这种方式写入 HTTP 流。

bstrToken    = L"DATA";
index        = vecServerCtx.Find(bstrToken);
if (index > -1)
{    
    map = vecServerCtx[index].GetValueAsMap();
    if (!map.empty())  //we have values
    for (itMap = map.begin(); itMap != map.end(); itMap++) 
        *pCtxt    <<    (*itMap).first    << " = " 
                  <<    (*itMap).second    << "br";
}

Sample Image     

可以直接获取所需参数的值:

*pCtxt << "Filename = " << map[L"Filename"] << "br".

TwinVector 类提供了 VARIANT GetVariant() 方法和 TwinVector(VARIANT varSafe) 构造函数,以便轻松地在 COM+ 组件之间通过网络传输集合。

非 MFC 版本

非 MFC 版本基于 MSDN 关于 ISAPI 扩展中 GET-POST 数据的文章。

C++ 扩展在 DWORD WINAPI HttpExtensionProc( LPEXTENSION_CONTROL_BLOCK pECB ) 方法中接收入口点。

在这里,它调用 CWriteFormExtension 类的 Run 方法——我们的 ISAPI 扩展中只有一个运行对象。

用于在数据集合中保存参数的 C++ 类是 MultipartParser 和 MultipartEntry。继承的 Map STL 类型的 cParser 变量接收整个 POST 数据集合。这是在 Initialize 方法中完成的。GetParam 是一个返回所需参数值的辅助方法。

String CWriteFormExtension::GetParam(MultipartParser& cParser, String sName)
{
    String           sValue; //the output string
    MultipartEntry*  pEntry  = cParser[sName.c_str()];

    if(pEntry != NULL)     //we have data
    {
        sValue = (LPCTSTR) pEntry->Data();    //get value from collection        
        int nLen = sValue.size();
        
        if(sValue[nLen - 1] == '\n' && sValue[nLen - 2] == '\r')
        sValue = sValue.substr(0, nLen - 2);
    }
    return sValue;
}

这是 Run 方法的结果

Sample Image

LoadLongResource 私有函数与 MFC 版本相比略有修改。输入输出 str 字符串参数是 STL string 类型。在 szPath char 变量中,我们必须放入 DLL 文件的名称,以便加载正确的资源库。

BOOL CWriteLayoutExtension::LoadLongResource(String &str, UINT nID)
{
    HRSRC               hRes;
    BOOL                bResult            = FALSE;
    CHAR                szPath[MAX_PATH];
    
    strcpy(szPath, "WriteForm.dll");
    HINSTANCE hInst = LoadLibrary(szPath);

    //if you want standard html type
    hRes = FindResource(hInst, MAKEINTRESOURCE(nID), RT_HTML);    
    if (hRes == NULL)
    {    
         //trace error
        str = "Error: Resource could not be found\r\n";
    }
    else
    {    
        DWORD dwSize = SizeofResource(hInst, hRes);
        if (dwSize == 0)
        {    
            str.empty();
            bResult = TRUE;
        }
        else
        {    
            HGLOBAL hGlob = LoadResource(hInst, hRes);
            if (hGlob != NULL)
            {    
                LPVOID lpData = LockResource(hGlob);
                if (lpData != NULL)
                {    
                    str            = (LPCTSTR)lpData;    
                    bResult        = TRUE;
                }
                FreeResource(hGlob);
            }    
        }
        if (!bResult)
        str = "Error: Resource could not be load\r\n";
    }
    return bResult;
}

历史

  • 2002 年 7 月 16 日 - 更新了 MFC.zip 下载(缺少一个类)

许可证

本文未附加明确的许可证,但可能在文章文本或下载文件本身中包含使用条款。如有疑问,请通过下面的讨论区联系作者。

作者可能使用的许可证列表可以在此处找到。

© . All rights reserved.