首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Coldfusion onCFCRequest将XML的返回类型转换为WDDX

Coldfusion onCFCRequest将XML的返回类型转换为WDDX
EN

Stack Overflow用户
提问于 2014-04-02 00:50:05
回答 2查看 1.3K关注 0票数 4

我的客户群终于离开了Coldfusion8,所以现在我可以利用Coldfusion9的Application.cfc -> onCFCRequest事件了。我有一个测试场景设置,我的结果与我所期望的不一样。我有一个我调用的方法,它产生一个有效的XML响应,类似于.

代码语言:javascript
运行
复制
Response Header: Content-Type:application/xml;charset=UTF-8
Response:
<?xml version="1.0" encoding="UTF-8"?>
<rows><row id="10000282742505"><cell/><cell> ...

现在,在我介绍了onCFCRequest事件之后,我得到了它(它破坏了我的网格)..。

代码语言:javascript
运行
复制
Response Header: Content-Type:application/xml;charset=UTF-8
Response:
<wddxPacket version='1.0'><header/><data><string>&lt;rows&gt;&lt;row id="10000282742505"&gt;&lt;cell&gt;&lt;/cell&gt;&lt;cell&gt; ...

这是一个活动..。

代码语言:javascript
运行
复制
<cffunction name="onCFCRequest" access="public" returntype="Any" output="true">
    <cfargument type="string" name="cfc" required="true">
    <cfargument type="string" name="method" required="true">
    <cfargument type="struct" name="args" required="true">

    <cfscript>
        // OnCFCRequest security hole fix as detailed here: http://blog.adamcameron.me/2013/04/its-easy-to-create-security-hole-in.html
        var o = createObject(ARGUMENTS.cfc);
        var metadata = getMetadata(o[ARGUMENTS.method]);

        if (structKeyExists(metadata, "access") && metadata.access == "remote"){
            return invoke(o, ARGUMENTS.method, ARGUMENTS.args);
        }else{
            throw(type="InvalidMethodException", message="Invalid method called", detail="The method #method# does not exists or is inaccessible remotely");
        }
    </cfscript>
    <cfreturn />
</cffunction>

如何让onCFCRequest以远程函数返回的相同格式传递响应?

我知道这篇文章:http://www.bennadel.com/blog/1647-Learning-ColdFusion-9-Application-cfc-OnCFCRequest-Event-Handler-For-CFC-Requests.htm

我可能最终会尝试这样做,但首先我想弄清楚为什么我不能简单地以相同的格式传递响应。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-04-03 15:58:51

看来我不能简单地用同样的格式传递结果,因为.“默认情况下,ColdFusion将所有返回类型(包括简单返回类型)序列化为WDDX格式,并以XML形式返回XML数据。”(US/ColdFusion/9.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-7f5c.html)。正在调用的远程函数将我的xml作为字符串返回给onCFCRequest,然后onCFCRequest将简单的返回类型(此时的字符串)转换为WDDX,因为这是默认行为。

所以..。

经过大量的测试后,我最终使用了Ben的文章中的解决方案,但我想提一下一些调整。

  1. 第一个补充是为Adam发现的bug添加已经在我的问题中显示的代码。
  2. 第二个附加项是在调用:<cfset local.result = ToString(local.result)>之后立即执行此操作。在Ben的注释中,它说"...all返回的值将是字符串.“但情况似乎并非如此。我们有一些远程函数只返回一个数字。如果没有ToString(),将响应转换为二进制文件的代码会失败。
  3. 在设置mimeTypes的部分中,我更改了json的IF语句。在我们编写的每个远程函数中,我们创建一个ColdFusion结构,然后返回如下:<cfreturn SerializeJSON(z.response) />。这似乎比手工拼凑一个json字符串,然后在onCFCRequest中序列化它要容易得多。因此,在用于json的onCFCRequest中,我只是把它当作一个字符串来处理,因为它已经序列化了;所以不需要第二次序列化它。
  4. 同样在mimeType部分中,我为xml添加了一个IF语句。我们有许多远程函数,它们将xml用于网格,而不是wddx。由于没有returnFormat of xml,所以我在wddx检查前面为returnType of xml添加了一个检查。
  5. 根据@Henry的评论,将responseMimeType for JSONXML改为application/jsonapplication/xml。谢谢!

非常感谢本和亚当把地面工作做好了!

这是最终结果..。

代码语言:javascript
运行
复制
<cffunction name="onCFCRequest" access="public" returntype="void" output="true" hint="I process the user's CFC request.">
    <cfargument name="component" type="string" required="true" hint="I am the component requested by the user." />
    <cfargument name="methodName" type="string" required="true" hint="I am the method requested by the user." />
    <cfargument name="methodArguments" type="struct" required="true" hint="I am the argument collection sent by the user." />

    <!---
    Here we can setup any request level variables we want
    and they will be accessible to all remote cfc calls.
    --->
    <cfset request.jspath  = 'javascript'>
    <cfset request.imgpath = 'images'>
    <cfset request.csspath = 'css'>

    <!---
    Check to see if the target CFC exists in our cache.
    If it doesn't then, create it and cached it.
    --->
    <cfif !structKeyExists( application.apiCache, arguments.component )>

        <!---
        Create the CFC and cache it via its path in the
        application cache. This way, it will exist for
        the life of the application.
        --->
        <cfset application.apiCache[ arguments.component ] = createObject( "component", arguments.component ) />
    </cfif>

    <!---
    ASSERT: At this point, we know that the target
    component has been created and cached in the
    application.
    --->

    <!--- Get the target component out of the cache. --->
    <cfset local.cfc = application.apiCache[ arguments.component ] />

    <!--- Get the cfcs metaData --->
    <cfset var metadata = getMetaData( local.cfc[ arguments.methodName ] )>

    <!--- OnCFCRequest security hole fix as detailed here: http://cfmlblog.adamcameron.me/2013/04/its-easy-to-create-security-hole-in.html --->
    <cfif structKeyExists(metadata, "access") and metadata.access eq "remote">
        <!--- Good to go! --->
    <cfelse>
        <cfthrow type="InvalidMethodException" message="Invalid method called" detail="The method #arguments.methodName# does not exists or is inaccessible remotely">
    </cfif>

    <!---
    Execute the remote method call and store the response
    (note that if the response is void, it will destroy
    the return variable).
    --->
    <cfinvoke returnvariable="local.result" component="#local.cfc#" method="#arguments.methodName#" argumentcollection="#arguments.methodArguments#" />

    <!---
    We have some functions that return only a number (ex: lpitems.cfc->get_lpno_onhandqty).
    For those we must convert the number to a string, otherwise, when we try to
    convert the response to binary down at the bottom of this function it will bomb.
    --->
    <cfset local.result = ToString(local.result)>

    <!---
    Create a default response data variable and mime-type.
    While all the values returned will be string, the
    string might represent different data structures.
    --->
    <cfset local.responseData = "" />
    <cfset local.responseMimeType = "text/plain" />

    <!---
    Check to see if the method call above resulted in any
    return value. If it didn't, then we can just use the
    default response value and mime type.
    --->
    <cfif structKeyExists( local, "result" )>

        <!---
        Check to see what kind of return format we need to
        use in our transformation. Keep in mind that the
        URL-based return format takes precedence. As such,
        we're actually going to PARAM the URL-based format
        with the default in the function. This will make
        our logic much easier to follow.

        NOTE: This expects the returnFormat to be defined
        on your CFC - a "best practice" with remote
        method definitions.
        --->
        <cfparam name="url.returnFormat" type="string" default="#metadata.returnFormat#" />
        <cfparam name="url.returnType" type="string" default="#metadata.returnType#" /> <!--- Added this line so we can check for returnType of xml --->

        <!---
        Now that we know the URL scope will have the
        correct format, we can check that exclusively.
        --->
        <cfif (url.returnFormat eq "json")>
            <!--- Convert the result to json. --->
            <!---
            We already serializeJSON in the function being called by the user, this would cause double encoding, so just treat as text
            <cfset local.responseData = serializeJSON( local.result ) />
            --->
            <cfset local.responseData = local.result />
            <!--- Set the appropriate mime type. --->
            <cfset local.responseMimeType = "application/json" />
        <!---
        There is no returnFormat of xml so we will check returnType instead.
        This leaves the door open for us to use wddx in future if we decide to.
        --->
        <cfelseif (url.returnType eq "xml")>
            <!--- Convert the result to string. --->
            <cfset local.responseData = local.result />
            <!--- Set the appropriate mime type. --->
            <cfset local.responseMimeType = "application/xml" />
        <cfelseif (url.returnFormat eq "wddx")>
            <!--- Convert the result to XML. --->
            <cfwddx action="cfml2wddx" input="#local.result#" output="local.responseData" />
            <!--- Set the appropriate mime type. --->
            <cfset local.responseMimeType = "application/xml" />
        <cfelse>
            <!--- Convert the result to string. --->
            <cfset local.responseData = local.result />
            <!--- Set the appropriate mime type. --->
            <cfset local.responseMimeType = "text/plain" />
        </cfif>

    </cfif>

    <!---
    Now that we have our response data and mime type
    variables defined, we can stream the response back
    to the client.
    --->

    <!--- Convert the response to binary. --->
    <cfset local.binaryResponse = toBinary( toBase64( local.responseData ) ) />

    <!---
    Set the content length (to help the client know how
    much data is coming back).
    --->
    <cfheader name="content-length" value="#arrayLen( local.binaryResponse )#" />

    <!--- Stream the content. --->
    <cfcontent type="#local.responseMimeType#" variable="#local.binaryResponse#" />

    <!--- Return out. --->
    <cfreturn />
</cffunction>
票数 1
EN

Stack Overflow用户

发布于 2014-04-02 07:34:58

我从来没有用过onCfcRequest,但你说得对,它有点蠢。

似乎onCfcRequest也会“吞下”returnFormat,因此您必须实现自己的returnFormat检测,并将其序列化为正确的格式。

ReturnType的OnCFCRequest()方法应该是无效的,就像它的OnRequest()反部分一样。从此方法返回值似乎对页面响应中实际返回的内容没有任何影响。要返回一个值,您必须在方法体中输出它,或者通过CFContent返回它。

引用自:http://www.bennadel.com/blog/1647-Learning-ColdFusion-9-Application-cfc-OnCFCRequest-Event-Handler-For-CFC-Requests.htm

例如。

代码语言:javascript
运行
复制
...
var result = invoke(o, ARGUMENTS.method, ARGUMENTS.args);
...
<!--- after your </cfscript> --->

<!--- TODO: do some checking to determine the preferred return type --->

<!--- if detected as xml, serve as xml (safer option) --->
<cfcontent type="application/xml" 
           variable="#toBinay(toBase64(local.result))#">

<!--- *OR* (cleaner version) watch out for white spaces --->
<cfcontent type="application/xml">
<cfoutput>#result#</cfoutput>

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22799587

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档