【问题标题】:Javascript error when html passed in JSON packethtml 传入 JSON 数据包时出现 Javascript 错误
【发布时间】:2011-04-12 16:23:20
【问题描述】:

我要疯了,试图解决这个问题。我已经实现了一个类似于 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为什么要做双引号??有人有什么想法吗?

【问题讨论】:

  • 不要使用eval,使用真正的JSON解析器:github.com/douglascrockford/JSON-js
  • 如果您向我们展示一些 JSON 而不是一些生成 JSON 的 CF,将会有所帮助。
  • 再次嗨 - 事实上,我确实在其他地方为我的 ajax 使用了 JSON 解析器,但我不确定在这种情况下你会如何使用它,因为没有真正的 ajax 发生。

标签: javascript jquery json coldfusion


【解决方案1】:

HTML 是响应被解释为格式错误的 HTML。 SerializeJSON 将 "&lt;/div&gt;" 中的“/”转义为 "&lt;\/div&gt;",导致 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#" />

在浏览器中使用

找到 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() + ")" );

【讨论】:

  • 感谢您的建议,但在我尝试使用您的建议的每次测试中,数据都是空的。
  • @Paul Perigny:嗨,Paul - 好的,请取消我之前的评论。睡了一会儿后,我再次查看了您的解决方案,发现我遗漏了 'var objUploadBody = window.frames[ strName ].document.getElementById( "data" );' 这一行测试时。我现在再次测试,并设法使用您的建议使其工作,除了我在javascript“无效标签”中遇到错误,它似乎与数据一起出现。我会调查的。但是,到目前为止,即使出现错误,一切都正常,因此现在只需删除此错误即可。
  • @Paul Perigny:好的,Paul,我确定正是您用来传递数据的
  • 抱歉,我忘记将类型添加到脚本块中。应该是:&lt;script id="data" type="json"&gt;。这将阻止浏览器尝试将脚本块解释为 JavaScript。
  • @Paul Perigny:你是救生员!非常感谢你!它正在工作。我不得不删除 HtmlEditFormat() 包装器,但是一旦我将类型添加到脚本标记中就可以了。有趣的是,我似乎记得我第一次看到你的帖子时包含 type 属性??无论如何,它正在工作,我很高兴!再次感谢:)
【解决方案2】:

我得到的 javascript 错误通常是 类似于:“未终止的常规 表达式字面量"

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

【讨论】:

  • 嗨 - 你是正确的。请参阅上面的更新。我发布了不正确的 JSON。它是由 Coldfusion 生成的,所以我不确定为什么输出时带有双引号??
【解决方案3】:

您将 JSON 推送到 HTML 文档的 &lt;body&gt; 中。

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

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

因此解决方案是:

  1. 对 JSON 中的任何实体进行编码。您需要 JSON 字符串的 HTML 表示,而不是原始字符串。我不知道如何在 CF 中执行此操作,但必须有一个等效于 encode_entities / htmlspecialchars / 等
  2. 获取text() 而不是html()

(顺便说一句:这就是您需要做的一切,而不是替代列表)

【讨论】:

  • 嗨,大卫。我已经根据此处的建议尝试了所有可能的组合,使用 .html()、.text()、删除 eval()、删除 SerializeJson() 等。每次都是一个或另一个 javascript 错误。但是,我已经实现了您对代码中已更新的 HtmlEditFormat() 的建议,但即使是所有其他组合也无济于事。我倾向于认为它肯定与 JSON 输出有关。
【解决方案4】:

问题在于您将来自服务器的 JSON 响应嵌入到更多 html 中。 AJAX 调用的 JSON 响应应该包含 ONLY JSON 文本,没有其他内容。

由于您将其嵌入到 HTML 中,然后通过 DOM 调用检索它,因此浏览器很可能完全被 html 中的 json 中的 html 和 DOM 弄乱了。

试试这个吧:

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

var objData = eval(jBody);

但是,正如其他答案所指出的那样,您不应为此使用 eval 。有比 eval 更安全的方法将 JSON 数据解析回 javascript 对象。

【讨论】:

  • 您好,这不是ajax调用,而是使用html框架提交内容并接收响应的类ajax调用。尽管如此,我尝试了您的建议,以及您和其他所有人的建议,但到目前为止都没有运气。
猜你喜欢
  • 1970-01-01
  • 2019-08-13
  • 2016-08-18
  • 2019-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-22
相关资源
最近更新 更多