【原创】记一次AJAX请求TP5接口解析JSON失败问题

作者Veris 文章分类 分类:PHP 文章评论 0条评论 阅读次数 已被围观 5343

小V在写API接口时发生了个问题:使用jquery的ajax请求地址返回如下字符串,导致无法被dataType="json"解析为json格式

"{\"code\":0,\"msg\":\"创建预支付码成功!\",\"data\":\"weixin:\\\/\\\/wxpay\\\/bizpayurl?pr=JuQfNMM\",\"timestamp\":1510588707}"

起初以为是ajax问题,搜索了相关的文章,有几个针对不解析json格式的原因:

1、JQuery版本问题,JQuery1.4对json的格式有着严格的要求,所有的键值都要用双引号标起来,说明文档原文

"json": Evaluates the response as JSON and returns a JavaScript object. In jQuery 1.4 the JSON data is parsed in a strict manner; any malformed JSON is rejected and a parse error is thrown. (See json.org for more information on proper JSON formatting.) 

2、dataType的值不能为大写,也就是不应该是“JSON”而是“json”

以上两个原因我都试过解决方案,经过试验并不是这些问题;我又使用postman工具对接口进行测试,发现“\”反斜杠的情况并未发生,而且直接在浏览器上访问接口地址也没有问题,这就引发了我的深(怒)思(),wtf,为啥子会这样!!

return J(0,'创建预支付码成功!',$prepay_id);

分析一下我的PHP代码,J函数是我定义的:

/**
 * 返回接口数据
 * @param int $code 状态码
 * @param string $msg 信息
 * @param array $data 数据
 * @return string json数据
 */
function J($code,$msg,$data=[])
{
    return json_encode([
        'code'      =>$code,
        'msg'       =>$msg,
        'data'      =>$data,
        'timestamp' =>time()
    ],JSON_UNESCAPED_UNICODE);
}

我试着将代码改成:

die(J(0,'创建预支付码成功!',$prepay_id));

咦,居然正常了,ajax访问解析没问题!

这样不行啊,不搞清楚问题睡不着觉啊!我们知道直接return返回数据的方法是tp定义的,所以我摸着藤找到了tp实现return方法的代码:

thinkphp\library\think\App.php

// 输出数据到客户端
if ($data instanceof Response) {
    $response = $data;
} elseif (!is_null($data)) {
    // 默认自动识别响应输出类型
    $isAjax   = $request->isAjax();
    $type     = $isAjax ? Config::get('default_ajax_return') : Config::get('default_return_type');
    $response = Response::create($data, $type);
} else {
    $response = Response::create();
}

这里有个代码是做自动识别响应输出的,在默认配置中default_ajax_return="json",而default_return_type="html",这下我大概明白了,因为postman和直接访问接口地址都不是ajax类型,返回的当然都是html了,而使用ajax请求,则返回json类型的代码:

$response = Response::create($data, 'json');

再往下追下去就是thinkphp\library\think\response\Json.php

/**
 * 处理数据
 * @access protected
 * @param mixed $data 要处理的数据
 * @return mixed
 * @throws \Exception
 */
protected function output($data)
{
    try {
        // 返回JSON数据格式到客户端 包含状态信息
        $data = json_encode($data, $this->options['json_encode_param']);

        if ($data === false) {
            throw new \InvalidArgumentException(json_last_error_msg());
        }

        return $data;
    } catch (\Exception $e) {
        if ($e->getPrevious()) {
            throw $e->getPrevious();
        }
        throw $e;
    }
}

注意他得数据是用json_encode做处理的,而我的J函数也做了一次json_encode处理,我们知道json_encode会把引号中的引号前面加“\”,所以问题也就水落石出了。

这里说下TP5的return,TP5的口号是为API而生,所以对于数据输出那里做了一些改进,在配置文件中有两个选项:

// 默认输出类型
'default_return_type'    => 'html',
// 默认AJAX 数据返回格式,可选json xml ...
'default_ajax_return'    => 'json',

直接使用return 数组;用ajax去访问则能获取到json数据,而直接访问获取则会报错500,因为不能直接echo输出一个array。

搞了半天其实还是我的规范问题,这里总结一下tp5使用:

1、开发纯API网站,可使用return 数组; 的格式,但是此方法只适用于ajax状态访问,如果想在没有其他类型的请求下返回json,则将default_return_type设为json。

2、开发一般的但也有API业务的网站,这种情况比较复杂,可酌情使用统一的方法来开发,比较少问题:

方案一:如果API数据想使用return json_encode(数组);格式返回,则统一使用html输出将default_ajax_return设为html,这样就能在被ajax请求时使用html返回数据(否则会被json返回再次encode,造成“\”)。

方案二:如果API数据想使用return 数组;格式返回,则保留原有配置,但请确保客户端使用ajax方式请求(否则会报错)。

3、如不想那么麻烦,可以直接使用die(json_encode(数组));返回json数据。

=================================================

转载请注明出处:

作者:Veris

最族 [ http://www.mostclan.com ]

记录于 2017-11-14 01:02

分类:PHP
标签: JSON dataType

发表评论: