在JSON数据包中传递html时出现Javascript错误

时间:2011-04-12 16:23:20

标签: javascript jquery json coldfusion

我很想解决这个问题。我已经实现了类似Coldfusion Ajax的文件上传,它使用隐藏框架上传文件,然后抓取框架返回的内容。它基于这篇文章:http://www.bennadel.com/blog/1244-ColdFusion-jQuery-And-AJAX-File-Upload-Demo.htm

因此,当我在数据中发回HTML时,一切都运行良好。因此,如果您查看下面的代码,我已经提供了将数据流回到隐藏框架的操作页面。第一行有效,第二行有html没有。

    <!--- Create the return HTML. Remember, we are going to be treating the BODY of the returned document as if it were a JSON string. --->
    <cfsavecontent variable="strHTML">

        <cfset var sResponse = {} />
        <!--- THIS WORKS --->
        <cfset sResponse = {SUCCESS = true, ERRORS = [], DATA = "Hello World", RETURNID=""} />
        <!--- THIS DOES NOT WORK --->
        <cfset sResponse = {SUCCESS = true, ERRORS = [], DATA = #HtmlEditFormat('<div>Hello World</div>')#", RETURNID=""} />

        <cfoutput>
            <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
            <html>
            <head></head>
            <body>#SerializeJSON( sResponse )#</body>
            </html>
        </cfoutput>
    </cfsavecontent>

<!--- Create binary response data. --->
<cfset binResponse = ToBinary( ToBase64( strHTML ) ) />

<!--- Tell the client how much data to expect. --->
<cfheader name="content-length" value="#ArrayLen( binResponse )#" />

<!--- Stream the "plain text" back to the client .--->
<cfcontent type="text/html" variable="#binResponse#" />

执行所有这些操作的javascript如下所示。传回HTML时出错的行是:

//假设我们的返回数据是JSON格式,请评估body html以获取我们的返回数据。 var objData = eval(“(”+“jBody.html()+”)“);

//ShareForm Photo Upload Form Process (simulated Ajax)
$(document).ready(function() {
    // Attach an event to the submit method. Instead of submitting the actual form to the primary page, we are going to be submitting the form to a hidden iFrame that we dynamically create.
    $( "#frmShareForm" ).submit(
        function( objEvent ){
            var jThis = $( this );
            var photoUploadAction = $("#photoUploadAction").val();

            // Create a unique name for our iFrame. We can do this by using the tick count from the date.
            var strName = ("uploader" + (new Date()).getTime());

            // Create an iFrame with the given name that does not point to any page - we can use the address "about:blank" to get this to happen.
            var jFrame = $( "<iframe name=\"" + strName + "\" src=\"about:blank\" />" );

            // We now have an iFrame that is not attached to the document. Before we attach it, let's make sure it will not be seen.
            jFrame.css( "display", "none" );

            // Since we submitting the form to the iFrame, we will want to be able to get back data from the form submission. 
            // To do this, we will have to set up an event listener for the LOAD event of the iFrame.
            jFrame.load(
                function( objEvent ){
                    // Get a reference to the body tag of the loaded iFrame. We are doing to assume that this element will contain our return data in JSON format.
                    var objUploadBody = window.frames[ strName ].document.getElementsByTagName( "body" )[ 0 ];

                    // Get a jQuery object of the body so that we can have better access to it.
                    var jBody = $( objUploadBody );

                    // Assuming that our return data is in JSON format, evaluate the body html to get our return data.
                    var objData = eval( "(" + jBody.html() + ")" );
                    alert(objData);

                    // A JSON-format struct is returned that will be used to do callback functionality
                    SharePhotoAjaxResponseHandler(objData);

                    // Remove the iFrame from the document. Because FireFox has some issues with "Infinite thinking", let's put a small delay on the frame removal.
                    setTimeout
                    (
                        function()
                        {
                            jFrame.remove();
                        }, 100
                    );
                }
            );

            // Attach to body.
            $( "body:first" ).append( jFrame );

            // Now that our iFrame it totally in place, hook up the frame to post to the iFrame.
            jThis
                .attr( "action",  photoUploadAction)
                .attr( "method", "post" )
                .attr( "enctype", "multipart/form-data" )
                .attr( "encoding", "multipart/form-data" )
                .attr( "target", strName );
    });
});

我得到的javascript错误通常是这样的: “未终止的正则表达式字面”

我还尝试删除CFM页面上的SerialiseJson和javascript中的eval,这两者都会导致其他js错误。我也尝试删除周围的html以及将.html()更改为.text(),删除eval()以及所有这些的组合。没有运气。

有人可以告诉我问题是什么。我知道我不能遥远,因为它没有HTML。

由于

更新:我运行了Coldfusion通过JSON验证器生成的JSON输出,但由于(从我看到的)双引号,它失败了:

{""RETURNID"":"""",""DATA"":""&lt;div&gt;Hello World&lt;\/div&gt;"",""SUCCESS"":true,""ERRORS"":[]}

现在我真的不知道为什么Coldfusion会做双引号?有人有什么想法吗?

4 个答案:

答案 0 :(得分:2)

HTML是响应被解释为格式错误的HTML。 SerializeJSON将"</div>"中的“/”转义为"<\/div>",导致HTML解析器看到格式错误的HTML。 在javascript方面,"/div"看起来像一个错误的正则表达式。

为此,您必须强制浏览器不为您解释数据。 使用错误类型在脚本块中发送数据(因此浏览器不会运行脚本)。

在Coldfusion中:

<!--- Create the return HTML. Remember, we are going to be treating the BODY of the returned document as if it were a JSON string. --->
<cfsavecontent variable="strHTML">

    <cfset sResponse = {SUCCESS = true, ERRORS = [], DATA = "<div>Hello World</div>", RETURNID=""} />
    <cfoutput>
        <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
        <html>
        <head></head>
        <body><script id="data" type="json">#SerializeJSON( sResponse )#</script>
        </html>
    </cfoutput>
</cfsavecontent>

<!--- Create binary response data. --->
<cfset binResponse = ToBinary( ToBase64( strHTML ) ) />

<!--- Tell the client how much data to expect. --->
<cfheader name="content-length" value="#ArrayLen( binResponse )#" />

<cfcontent type="text/html" variable="#binResponse#" />

在broswer中使用

找到json源
var objUploadBody = window.frames[ strName ].document.getElementById( "data" );

// Get a jQuery object of the body so that we can have better access to it.
var jBody = $( objUploadBody );

// Assuming that our return data is in JSON format, evaluate the body html to get our return data.
var objData = eval( "(" + jBody.html() + ")" );

答案 1 :(得分:0)

  

我得到的javascript错误通常是   类似的事情:“不定期的常规   表达文字“

检查你的JSON。您可以通过JSONLint运行它以查看它是否有效。根据您的错误消息,它可能不是。

答案 2 :(得分:0)

您正在将JSON推送到HTML文档的<body>

浏览器会将其解释为HTML,并对其执行错误更正(将&转换为&amp;并丢弃您放置它们的地方不允许的元素。

然后使用jQuery的html()方法将其拉出来,这将获取HTML源代码而不是您想要的文本。

因此解决方案是:

  1. 对JSON中的任何实体进行编码。您需要JSON字符串的HTML表示形式,而不是原始字符串。我不知道如何在CF中执行此操作,但必须等同于encode_entities / htmlspecialchars / etc
  2. 获取text()而不是html()
  3. (顺便说一句:这就是你需要做的一切,而不是替代品清单)

答案 3 :(得分:0)

问题是你在服务器中嵌入了更多html的JSON响应。 AJAX调用的JSON响应应包含 JSON文本,而不包含任何其他内容。

由于你将它嵌入到HTML中,然后使用DOM调用来检索它,很可能浏览器完全被你在html中的hson中的html混淆并且破坏了DOM。

试试这个,而不是:

<cfoutput>#SerializeJSON( sResponse )#</cfoutput>

var objData = eval(jBody);
但是,正如其他回答所指出的那样,你不应该使用eval。有更安全的方法可以将JSON数据解析回javascript对象而不是eval。