【原创】记一次AJAX请求TP5接口解析JSON失败问题
小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
发表评论: