6

我最初将其发布为早先关于ColdFusion 2016 上的 Empty CGI.REDIRECT_URL 的这个问题的答案。在考虑之后,我想得更好,因为技术上没有回答 OP 的问题。相反,我决定把它变成一个单独的问题,尽管它更像是一个评论而不是一个问题。虽然这在技术上可能无法满足最小、完整和可验证示例的全部要求,并且人们可能会对我投反对票,但我认为无论如何它都是值得的,希望将来可能遇到此问题的 CFers更容易找到它. 从而防止他们对 CGI 结构/作用域的这种特殊行为一头雾水。

话虽如此,CGI 结构/范围与其他结构/范围有一些未记录的不一致行为。请注意,我个人并不认为这一发现归功于我,因为前段时间我在阅读Ben Nadel 的博客文章时偶然发现了这一点。所以我在这里发布的所有信息都已经很详细了,但我想在这里写一个很好的总结。

未记录的行为 1 - 与其他结构不同,如果 CGI 结构键不存在,则在引用它时不会引发错误。

OP 的原始问题中,他想知道为什么cgi.REDIRECT_URL存在但是是空的。正如他最终发现的那样,它从未真正存在过。作为一个单独的示例,您可以执行这行代码而不会引发错误。不是你所期望的,对吧?

<cfoutout>#cgi.THIS_IS_A_FAKE_KEY#</cfoutout>

那么CFer要做什么呢?测试密钥是否存在。

<cfif structKeyExists( CGI, 'THIS_IS_A_FAKE_KEY' )>
    THIS_IS_A_FAKE_KEY exists
<cfelse>
    THIS_IS_A_FAKE_KEY doesn't exist
</cfif>

未记录的行为 2 - 与其他结构不同,如果您转储 CGI 结构,它不会显示所有键/值对,它只会显示一组定义的键。

OP 的案例中,他有一个自定义 Apache CGI 变量cgi.REDIRECT_URL,在升级到 CF2016 之前在他的代码中使用,并且能够直接引用它。但是,我假设如果他倾倒了cgi结构,它就不会出现在转储中。在Ben Nadel 的案例中,他还有一个cgi名为的自定义变量,该变量cgi.document_root是从负载均衡器传递过来的,可以直接引用它,但在转储cgi内容时他也看不到密钥。

那么CFer要做什么呢?cgi理解这一点并将其存储在您的脑海中,这样当您转储内容并且键/值对不存在时您就不会被咬。除此之外,其他不多。

4

2 回答 2

8

我进入了cfusion.jarColdFusion的文件。我发现那里有点混乱。

CGI 范围并不是structure人们希望的那样。

这就是处理 CGI 变量调用的方式。例如<cfoutout>#cgi.THIS_IS_A_FAKE_KEY#</cfoutout>

  1. 正常有效的 CGI 范围变量是此列表中的变量,默认情况下这些变量将被初始化""

     private static final String[] names ="AUTH_PASSWORD","AUTH_TYPE","AUTH_USER","CERT_COOKIE","CERT_FLAGS","CERT_ISSUER","CERT_KEYSIZE","CERT_SECRETKEYSIZE","CERT_SERIALNUMBER","CERT_SERVER_ISSUER","CERT_SERVER_SUBJECT","CERT_SUBJECT","CF_TEMPLATE_PATH","CONTENT_LENGTH","CONTENT_TYPE","CONTEXT_PATH","GATEWAY_INTERFACE","HTTP_ACCEPT","HTTP_ACCEPT_ENCODING","HTTP_ACCEPT_LANGUAGE","HTTP_CONNECTION","HTTP_COOKIE","HTTP_HOST","HTTP_USER_AGENT","HTTP_REFERER","HTTP_URL","HTTPS","HTTPS_KEYSIZE","HTTPS_SECRETKEYSIZE","HTTPS_SERVER_ISSUER","HTTPS_SERVER_SUBJECT","LOCAL_ADDR","PATH_INFO","PATH_TRANSLATED","QUERY_STRING","REMOTE_ADDR","REMOTE_HOST","REMOTE_USER","REQUEST_METHOD","SCRIPT_NAME","SERVER_NAME","SERVER_PORT","SERVER_PORT_SECURE","SERVER_PROTOCOL","SERVER_SOFTWARE","WEB_SERVER_API" };`
    

    此外,所有这些值也来自各种 java 库javax.servletHttpServletRequest

  2. 如果经过一些检查后请求的变量不是这些变量中的任何一个,ColdFusion 就会转到请求标头。您可以使用getHttpRequestData().headers. 然后在密钥请求中查找带有连字符(-)而不是下划线(_)的密钥。cgi(如果密钥以 开头http_,则请求标头中的密钥将没有它,就像http_x_forward请求标头中的这样x-forward

     value = request.getHeader(name.replace('_', '-'));
    

据我所知,就 ColdFusion 而言,第一点提到的键被认为是 CGI 范围的一部分。但是,当从 Apache 负载平衡器服务器向 ColdFusion 传递附加信息时,这些信息最终会出现在请求标头中。由于 javagetHeader只返回一个空白字符串(或具有数据类型的东西undefined)而不是未定义的错误,因此 ColdFusion 不会识别任何键是否已定义

因此,如果密钥THIS_IS_A_FAKE_KEY是从 Apache 服务器等中介发送到 ColdFusion 的。您会在范围转储中找到getHttpRequestData().headers['THIS-IS-A-FAKE-KEY']但不在CGI范围转储中。

话虽如此,我个人的观点是,最好直接检查getHttpRequestData().headers自定义 CGI 变量而不是范围本身。

于 2018-02-15T07:09:17.040 回答
7

编辑感谢 Ageax 指出我的一个测试用例在我之前对这篇文章的修订中是无效的。

伟大的侦探工作RRK!所以我决定做一个实验,通过创建两个循环来验证你的发现。第一个循环将显示来自的键/值对,getHttpRequestData().headers第二个循环使用范围中的相应键/值对执行相同的操作,方法是cgi将 替换-_。瞧!正如 RRK 报告的那样,我们可以看到如何通过任何一种方法获取值。我做了一个更新的要点,并在这里发布给任何感兴趣的人。

<cfset httpHeaders = getHttpRequestData().headers>

<h3>getHttpRequestData().headers</h3>

<cfloop collection="#httpHeaders#" item="key" >
    <cfoutput><strong>#Key#</strong> : #httpHeaders[key]#<br></cfoutput>
</cfloop>

<h3>cgi keys dash to underscore</h3>

<cfloop collection="#httpHeaders#" item="key" >
    <cfset keyUnderscore = replace(key, "-", "_", "all")>
    <cfoutput><strong>#keyUnderscore#</strong> : #cgi[keyUnderscore]#<br></cfoutput>
</cfloop>
于 2018-02-15T14:35:10.443 回答