我正在尝试将一个旧的 CGI 应用程序从现有的 Windows 2003 服务器(IIS 6.0)迁移到运行良好的新 Windows 2008 服务器(IIS 7.0),但我们遇到了以下问题:
设置模块处理程序和所有内容后,我发现只有通过 POST 请求(从另一个页面提交表单)调用它时,我才能访问 CGI 应用程序(rdbweb.exe)文件。
如果我只是尝试输入文件的 URL(发出 GET 请求),我会收到以下错误:
HTTP 错误 502.2 - 错误网关
指定的 CGI 应用程序行为不当,未返回完整的 HTTP 标头集。它返回的标头是“模块 rdbweb.exe 中的异常 EInOutError,位于 00039B44。I/O 错误 6。”。
对于我们的一位客户来说,这是一个非常老的应用程序。当我们试图打电话给供应商时,他们说我们需要支付约 3000 美元的年度支持费才能开始讨论。当然,我尽量避免这种情况!
注意:
- 如果我们创建一个提交给“rdbweb.exe”的普通 HTML 表单,CGI 就可以正常工作。但是我们不能用这种方法作为解决方法,因为应用程序中的某些页面链接到“rdbweb.exe”时使用的是普通链接,而不是表单提交。
- 如果我们从控制台(命令提示符)窗口而不是 IIS 运行“rdbweb.exe”,我们会得到我们通常期望的正常 HTML,没有问题。
我们尝试了以下方法:
- 确保在 IIS 中映射到“rdbweb.exe”的 CGI 模块启用了所有权限(读取、写入、执行),并且允许所有动词而不仅仅是特定的动词,还尝试明确允许 GET、POST。
- 确保应用程序布尔值已将“启用 32 位应用程序”设置为 true。确保网站使用对“rdbweb.exe”文件和整个网站具有完全权限的帐户运行(尽管我们知道“读取”、“执行”应该足够了)。
- 确保计算机范围的 IIS 设置“ISAPI 和 CGI 限制”具有“rdbweb.exe”的完整路径。
- 将模块从 CGI 更改为 Fast CGI,同样不起作用
- 确保我们拥有最新的 Windows 更新(对于 IIS6,我们发现知识库文章指出需要针对 IIS6 进行修补的错误,但对于 IIS7 没有发现类似的错误)。
现在我们唯一能想到的可能性就是以下 Microsoft 知识库文章:http://support.microsoft.com/kb/145661- 内容如下:
CGI 错误:指定的 CGI 应用程序行为不当,未返回完整的 HTTP 标头集。它返回的标头如下:
文章提出了以下解决方案:
修改 CGI 应用程序标头输出的源代码。以下是正确标头的示例:
print "HTTP/1.0 200 OK\n"; print "Content-Type: text/html\n\n\n";
不幸的是我们没有资源来尝试这一点,我也不确定我们是不是遇到了这个问题。
您能帮我解决这个问题吗?有没有办法让应用程序在不需要 POST 请求的情况下工作?请注意,在旧的 IIS6 服务器上,该应用程序运行良好,我找不到任何特殊的 IIS 配置,我可能想在 IIS7 上尝试其等效配置。
答案1
简而言之:它可能是使用 D2007 最新更新(11.0.2902.10471)之前的 Delphi 版本编译的 Delphi CGI 应用程序。如果是这种情况,您需要源代码和 Delphi 安装并重新编译该应用程序。或者,您应该要求他们使用最新的 Delphi 版本重新编译该应用程序。
(从http://forums.iis.net/t/1100323.aspx?PageIndex=2)
我们找到了导致我们的 CGI 在 IIS 7 上不响应的问题。实际上,我们将原因缩小到所有用 Delphi 编写的 CGI 应用程序(至少到 2005 版)基类中的一行代码。此行代码位于 TCGIApplication 的 Run 方法中,只是重置标准输入。在 IIS 6 及更早版本上,此行执行没有问题,但在 IIS 7 上会引发异常,导致 CGI 应用程序崩溃,因此无法响应请求。我们仍在调查注释掉此行的副作用,但这是我们目前的解决方案。通过删除此行,我们的 CGI 应用程序现在可以在 IIS 7 上正确执行。
原作者:史蒂文
答案2
我们有一个 Delphi 5 CGI 应用程序在 IIS 7 上遇到了同样的问题。我们的解决方案与 Steven 上面发布的解决方案类似,但是,我们并没有完全注释掉 marius 上面提到的行。当我这样做时,我发现任何 Request.ContentString 语句都会在应用程序中返回一个空字符串。我们的解决方案是实施建议的代码修复本文靠近底部。供您参考,以下是我们对 CGIApp.pas 副本进行更改后的代码片段。
procedure TCGIApplication.Run;
var
HTTPRequest: TCGIRequest;
HTTPResponse: TCGIResponse;
begin
inherited Run;
if IsConsole then
begin
Rewrite(Output);
//Win 7/2008 IIS7
//Reset(Input);
{$i-} {!!IIS7}
Reset(Input);
if IOResult <>0 then ;
{$i+}
end;
try
HTTPRequest := NewRequest;
try
HTTPResponse := NewResponse(HTTPRequest);
try
HandleRequest(HTTPRequest, HTTPResponse);
finally
HTTPResponse.Free;
end;
finally
HTTPRequest.Free;
end;
except
HandleServerException(Exception(ExceptObject), FOutputFileName);
end;
end;
答案3
CGI 供应商确认该应用程序与 IIS 7.0 不兼容,他们将在未来的版本中支持它。
我认为这表明唯一的解决方法是 Microsoft 知识库文章中提到的代码更改。
答案4
我遇到了这个问题(CGI GET 无法与 Delphi 生成的 CGI 一起使用),而且我还想将 CGI 的扩展名保留为 .cgi 而不是 .exe(这会让用户感到害怕!)。IIS 7.5 似乎不允许 CGI 使用除 .exe 或 .dll 之外的扩展名。
这里有一个涉及 PHP(!) 的超级巧妙的解决方案:
基本上,您将让 PHP 调用您的 CGI 并回显结果。
在您的 IIS 配置中,将 *.cgi 映射到 php,就像将 *.php 映射到 php 一样。不要直接调用 CGI,而是使用以下 PHP 代码调用 .cgi 文件:
<?php
putenv('QUERY_STRING=' . $_SERVER['QUERY_STRING']);
echo system('C:... path your cgi...//...delphicgi.exe');
?>
用您原来的 Delphi CGI 替换“C:... path your cgi...//...delphicgi.exe”。
就是这样!您的用户不会注意到任何差异。显然,通过 PHP 进行操作会对性能造成影响。但至少您不需要重建 CGI,而且可以使用 .cgi 扩展名!