javascript - 正确返回带有嵌入 JS 函数的 JSON 对象

标签 javascript php ajax json flot

更新帖子

我有一个解决该问题的解决方案,到目前为止,该解决方案对我有效(仅在 Firefox 上进行了测试)。 我的主要目标是使用 Ajax 动态更新 Flot 图表。我还需要动态更新轴样式,您可以通过 tickFormatter 选项来完成此操作。为了避免我以前遇到的问题,我只需在 PHP 数组中插入所需的返回字符串,并对该数组进行 JSON 编码。返回 Ajax 函数后,我使用 javascript Function() 构造函数 ( Link ) 创建一个新函数。我希望这对某人有帮助。

Ajax

$.ajax({
    url: 'someControllerWhichCreatesJSONdata',
    data: 'some Value',
    type: 'post',
    cache: false,
    datatype: 'json'
})
.success(function(data) {
    var datas = data[0];    // fetch data array
    var options = data[1];  // fetch options array
    var xReturn = options.xaxes[0].tickFormatter; // fetch return string
    var yReturn = options.yaxes[0].tickFormatter;        
    var xFunc = new Function("val", "axis", xReturn); // create function
    var yFunc = new Function("val", "axis", yReturn);
    options.xaxes[0].tickFormatter = xFunc; // update tickFormatter with function
    options.yaxes[0].tickFormatter = yFunc;

    $.plot($("#yw0"), datas, options);
})
.error(function(data) {
    $("#error").html(data.responseText); // show error in separate div
});

PHP 数组

$options = array(
    'legend' => array(
        'position' => 'nw',
        'show' => true,
        'margin' => 10,
        'backgroundOpacity' => 0.5
    ),
    'grid' => array(
        'clickable' => true,
        'hoverable' => true
    ),
    'pan' => array('interactive' => true),
    'zoom' => array('interactive' => true),
    'axisLabels' => array('show' => true),
    'xaxes' => array(
        array(
            'axisLabel' => 'someUnit',
            'tickFormatter' => 'return "foo bar"' // enter whatever return value you need
        )
    ),
    'yaxes' => array(
        array(
            'axisLabel' => 'someUnit',
            'tickFormatter' => 'return "foo bar"'
        )
    )
);

我跳过数据数组,因为它看起来很相似。两个数组都被组合并进行 JSON 编码。

public function actionSomeControllerWhichCreatesJSONdata() {
   $returnArray = array($data, $options);
   echo json_encode($returnArray);
   return true;
}

生成的数组看起来像我在这篇文章底部发布的数组。

原帖

我已经尝试了几个小时,但无法让它发挥作用。

我有一个 Ajax 请求,成功时它会获取一个 JSON 对象作为返回值。只要我不在 JSON 数组中使用 JS 函数,这个方法就可以正常工作。所以我的 JSON 数组如下所示(在 json_encode 之后):

[{
  "data": [{
    {1,2},
    {3,4},
  }],
  "function": "function(){return \"foo bar\";}"
}]

为了摆脱函数字符串中的 "。我使用 str_replace 并将带引号的字符串替换为不带引号的字符串。这看起来像这样:

[{
  "data": [{
    {1,2},
    {3,4},
  }],
  "function": function(){return "foo bar";}
}]

简单的 json_encode 工作正常,我的 Ajax 函数将其读取为 JSON 对象。替换字符串后,结果发现返回值不再是 JSON 对象,而是纯文本字符串。我尝试使用 jquery.parseJSON() 再次解析字符串,但这会导致语法错误:

SyntaxError: JSON.parse: unexpected keyword at line 1 column 396 of the JSON data

Ajax函数:

$.ajax({
    url: 'someControllerWhichCreatesJSONdata',
    data: 'some Value',
    type: 'post',
    cache: false,
    datatype: 'json' // or text when trying to parse
})
.success(function(data) {
    console.log(data);
    var dat = jQuery.parseJSON(data);  // trying to parse (only when dataType: "text")
    var datas = dat[0];                // or data[0] when datType = json
    var options = dat[1];              // ---
    $.plot($("#yw0"), datas, options); // trying to update a FLOT window
})
.error(function(data) {
    console.log("error");
    $("#error").html(data.responseText); // show error in separate div
});

因此,当使用此函数并将返回类型设置为“json”时,会产生错误。如果返回类型为 "text" 并且我尝试解析该字符串,则会收到上述错误。这个问题有什么解决方案吗?还是我做错了什么?

感谢您的帮助!

更新 抱歉,我的 JSON 数据当然无效!正如我所说,我的 JSON 对象是由 json_encode 创建的,我想它的语法应该是正确的。 son_encode 之后的纯数组如下所示:

[[{
   "data":[[0.0042612,0.0042612]],
   "label":"WISE.W3: Cutri et. al 2012",
   "lines":{"show":false},
   "points":{"show":true,"radius":3}}],
  {
   "legend": {
        "position":"nw",
        "show":true,
        "margin":10,
        "backgroundOpacity":0.5},
   "grid": {
        "clickable":true,
        "hoverable":true},
   "pan":{"interactive":true},
   "zoom":{"interactive":true},
   "axisLabels":{"show":true},
   "axisLabel": {
        "unit":"Jy",
        "id":null,
        "name":null},
   "tickFormatter":"$tickFormatter$",
   "position":"right"
}]

str_replace之后我得到了

[[{
   "data":[[0.0042612,0.0042612]],
   "label":"WISE.W3: Cutri et. al 2012",
   "lines":{"show":false},
   "points":{"show":true,"radius":3}}],
  {
   "legend": {
       "position":"nw",
       "show":true,
       "margin":10,
       "backgroundOpacity":0.5},
   "grid":{"clickable":true,"hoverable":true},
   "pan":{"interactive":true},
   "zoom":{"interactive":true},
   "axisLabels":{"show":true},
   "axisLabel":{"unit":"Jy","id":null,"name":null},
   "tickFormatter":function(val, axis){return val.toExponential(2)},
   "position":"right"
 }]

最佳答案

Adeno 已经指出,您的 JSON 语法无效。 请尝试使用 linter 验证您的 JSON,例如 http://jsonformatter.curiousconcept.com/

这样好一点:

[{"data":[["1","2"],["3","4"]],"function":"function(){return \"foo bar\";}"}]

另一件事是:您不应该手动反序列化 JSON。所有较新版本的 jQuery 将根据响应的内容类型 header 自动反序列化 JSON。

您已将 ajax 请求的 dataType 设置为 json。 响应是 JSON 并且将被反序列化。 这样就可以直接使用了

.success: function(response) {
    console.log(response.data);
    console.log(response.function);
}

回答评论中的问题/问题:

现在您再次创建了无效的 JSON,因为 "tickFormatter": function(val, axis){return val.toExponential(2)}, 错过了函数字符串周围的引号。

  • 在使用 str_replace() 插入字符串之前,需要注意转义和引用。 您可能需要一个小辅助函数,它可以正确转义字符串 - 成为有效的 JSON。
  • 您需要正确使用 str_replace():不替换外部引号,仅替换内部 $tickFormatter$

等等..我将提供一个例子:

    // we already have an array, which is JSON encoded
    // now you want to insert additional JSON content.
    // therefore we use a token replace approach.

    // valid JSON - with $token$

    $json = '[{"data":[["1","2"],["3","4"]],"tickFormatter":"$tickFormatter$"}]';

    // the (future) javascript function is a string.
    // it's not properly escaped or quoted to be JSON
    // this allows for copy and pasting JS into PHP
    $unescaped_functionString = 'function(){return "foo bar";}';

    // in order escapre properly, we need a json escaping helper

    /**
     * @param $value
     * @return mixed
     */
    function escapeJsonString($value) { # list from www.json.org: (\b backspace, \f formfeed)
        $escapers = array("\\", "/", "\"", "\n", "\r", "\t", "\x08", "\x0c");
        $replacements = array("\\\\", "\\/", "\\\"", "\\n", "\\r", "\\t", "\\f", "\\b");
        $result = str_replace($escapers, $replacements, $value);
        return $result;
    }

    // then we escape the function string

    $functionString = escapeJsonString($unescaped_functionString);

    // now its ready to be inserted into the existing JSON,
    // where token $tickFormatter$ is defined
    // the token must be in single quotes. you replace just the $token$ and not "$token$".

    $json = str_replace('$tickFormatter$', $functionString, $json);

    echo $json;

    // The result is valid JSON again:
    // [{"data":[["1","2"],["3","4"]],"tickFormatter":"function(){return \"foo bar\";}"}]

下一步: 发出ajax请求,json数据传输到客户端,您要执行您传入的函数。

所以新问题是“如何从字符串调用/执行 JavaScript 函数 - 不使用 eval?”

一般来说,隧道是一种不好的做法,请参阅:Is it valid to define functions in JSON results?

无论如何,有不同的方法可以做到这一点:

引用:http://everythingfrontend.com/posts/studying-javascript-eval.html

  • eval() - 邪恶,但有效。
  • setTimeout()

    setTimeout(" function ", 0); 
    
  • 新函数()

    var codeToExecute = "My.Namespace.functionName()";
    var tmpFunc = new Function(codeToExecute);
    tmpFunc();
    
  • 文档.write

    document.write('<script> JS </script>')
    
  • 数据 URI

    var s = document.createElement('script');
    s.src = 'data:text/javascript,' + encodeURIComponent('alert("lorem ipsum")')
    document.body.appendChild(s);
    

关于javascript - 正确返回带有嵌入 JS 函数的 JSON 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27766220/

相关文章:

javascript - 拒绝从 '*' 执行脚本,因为它的 MIME 类型 ('application/json' ) 不可执行,并且严格的 MIME 类型 che

javascript - D3.js 替换段落中的文本

php - 查找所有文本框值并发布到 PHP MySQL

php - Magento 是框架还是平台?

php - composer autoload.php 无法打开流 : no such file or directory

.NET Core 3.1 中使用 Fetch API 的 Ajax 调用

php - 如何在ajax过程中显示加载动画和禁用按钮

javascript - 扫描 Javascript 中的滥用功能和模式

javascript - 导航栏元素不折叠

javascript - AngularJS 和 CSS 过渡