小熊奶糖(BearCandy)
小熊奶糖(BearCandy)
发布于 2024-05-21 / 16 阅读
0
0

PHP thinkphp layui加thinkPHP为什么前端会自动解析PHP返回的数组为JSON?

在ThinkPHP框架中,要返回一个数据并将其自动转化为JSON格式,你可以直接在控制器的方法里返回一个数组。ThinkPHP框架会自动检测到AJAX请求,并使用内置的响应类自动将数组转换为JSON格式返回给客户端。以下是一个简单的示例:

// 假设这是你的控制器的一个方法
public function getData()
{
    // 创建一个数据数组
    $data = [
        'status' => 0,
        'message' => '操作成功',
        'data' => [
            'name' => '张三',
            'age' => 25,
            'email' => 'zhangsan@example.com'
        ]
    ];

    // 直接返回数组,ThinkPHP会自动将其转换为JSON格式响应给客户端
    return $data;
}

在这个例子中,当客户端通过AJAX请求访问这个 getData方法时,ThinkPHP框架会识别出这是一个AJAX请求,并自动将 $data 数组通过 Response 类的 json 方法处理,最终输出JSON格式的数据,如:

{
    "status": 0,
    "message": "操作成功",
    "data": {
        "name": "张三",
        "age": 25,
        "email": "zhangsan@example.com"
    }
}

需要注意的是,如果在某些特殊情况下需要手动控制输出JSON格式,或者需要调整JSON输出的选项(比如允许非UTF-8字符等),你可以使用:

return json($data, 200, [], JSON_UNESCAPED_UNICODE);

这里的 json 是ThinkPHP框架提供的快捷方法,它会自动设置响应头为 "application/json" 并输出JSON数据。第二个参数是HTTP状态码,默认为200,第三个参数是HTTP头部信息数组,默认为空,第四个参数是传递给 json_encode 的额外参数。

ThinkPHP框架实现自动将返回的数据转化为JSON格式,主要依赖于其内置的响应处理机制。下面是这一过程的基本原理:

  1. 自动识别请求类型:当一个请求到达ThinkPHP框架时,框架会首先判断这个请求是普通HTTP请求还是AJAX请求。这通常是通过检查请求头中的 X-Requested-With字段(对于大多数AJAX库而言,这个字段会被设置为 XMLHttpRequest)来实现的。
  2. 控制器返回数据:在控制器方法中,你直接返回一个数组或者对象。例如:
public function action() {
$data = ['result' => 'success', 'message' => '操作完成'];

return $data;

}
  1. 响应对象处理:ThinkPHP框架捕获到控制器返回的数据后,会使用其内置的 Response类来处理这个返回值。对于AJAX请求,框架会自动调用 Response类的相应方法将数据转换为JSON格式。这背后实际上是调用了PHP的 json_encode函数,将PHP数组或对象序列化为JSON字符串。
  2. 设置响应头:在将数据转换为JSON字符串后,框架还会自动设置HTTP响应头的 Content-Typeapplication/json;charset=utf-8,告知客户端返回的内容类型是JSON,并采用UTF-8编码。
  3. 输出数据:最后,框架会输出JSON格式的数据给客户端,前端的JavaScript就可以直接解析这些数据进行后续处理。

总结来说,ThinkPHP通过自动识别请求类型、使用响应对象处理返回数据、设置正确的响应头以及输出JSON数据,实现了无缝地将PHP数组转化为客户端可用的JSON格式。开发者无需手动进行JSON编码或设置响应头,简化了开发流程。

在PHP(包括ThinkPHP框架)中,当脚本遇到 return语句时,当前函数或方法的执行确实会停止,并返回指定的值给调用方。但这并不意味着整个PHP脚本立即终止运行。具体行为取决于 return所在的上下文:

  1. 在函数或方法内:如果 return位于一个函数或方法内部,它只会结束该函数或方法的执行,并将值返回给调用者。脚本的其他部分将继续执行,直到脚本自然结束或遇到其他终止指令(如另一个函数或脚本级别的 return,或者异常未被捕获)。
  2. 在脚本顶级或命名空间级别:如果 return是在全局作用域或命名空间级别使用,它会结束脚本的执行。这是因为此时没有更上层的代码来接收这个返回值,所以脚本直接停止运行。

在ThinkPHP框架中,当你在一个控制器方法内使用 return返回一个数组或对象时,这个操作实际上是告诉框架“这是我要返回给客户端的响应内容”。框架会处理这个返回值,将其转换为JSON(如果是AJAX请求)或渲染视图(如果是正常的页面请求),然后结束这次请求的处理。但是,这不会影响到其他并发请求或同一服务器上的其他脚本的执行。

例如,一个简单的ThinkPHP控制器方法可能是这样的:

public function index(){
$data = ['status' => 'success', 'message' => '操作完成'];
return $data; // 这里结束方法执行,但整个PHP进程或其它路由处理仍可能继续
}

在这个例子中,return使得控制器方法结束,但服务器上的其他操作(包括处理其他HTTP请求)不受影响。此外,如果在同一个请求生命周期内还有其他代码(比如过滤器、中间件等),它们会在所有控制器逻辑执行完毕后按顺序执行,除非之前的操作已经通过抛出异常或特定方式中断了执行流程。

举例:

总结:

1.json_encode()函数使用echo可以正常输出json,return 不会正常输出的原因是thinkphp会对return的数据进行二次处理(包括转义)而使用echo不会处理直接就输出来了( jquery ajax请求默认请求json格式)如果后端返回数组,不会报错。

例如1.0:

//定义命名空间
namespace app\controller;
//使用命名空间
use think\Request;
use \think\facade\Db;
class ApiAdmin
{
  
    public function index(Request $request,)
    {
                return json_encode(['code'=>0,'msg'=>$msg,'data'=>$data]); //输出的结果会被转义为字串
    }
}

例如1.1:

/定义命名空间
namespace app\controller;
//使用命名空间
use think\Request;
use \think\facade\Db;
class ApiAdmin
{
  
    public function index(Request $request,)
    {
                echo json_encode(['code'=>0,'msg'=>$msg,'data'=>$data]); //输出的结果会被转义为字串
    }
}

2.使用fetch请求(默认请求*/*,会返回整个html页面/text/html)

如果后端返回数组,fetch请求会报错

fetch("/index/testapi")
.then(res=>res.json())
.then(res=>{
   console.log('res',res)
})

可以定义herder来解决这个问题

fetch("/index/testapi"{
    herders:{
         'Accept':'application/json'
      }
})
.then(res=>res.json())
.then(res=>{
   console.log('res',res)
})

会向thinkphp发送请求头为json,这样thinkphp会返回一个json值,如果使用json_encode()会和Ajax一致,对返回的内容二次转义

可利用开发者工具查看请求头

正确无报错实例

AJAX实例

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>用户登录</title>
    <link rel="stylesheet" href="/static/admin/css/layui.css">
</head>

<body>

    <div class="continar">
        <div class="login">
            <form method="post" action="/apiadmin">
                <div class="title">
                    <h1>管理登录</h1>
                </div>
                <hr size="2px" width="100%" color="black">
                <div class="body">
                    <div class="input">
                        <label for="">用户登录</label>
                        <input type="text" name="username">
                    </div>
                    <div class="input">
                        <label for="">用户密码</label>
                        <input type="password" name="password">
                    </div>
                    <div class="input">
                        <input type="submit" name="提交">
                    </div>
                </div>
            </form>
        </div>
    </div>
</body>
<script src="/static/admin/js/layui.js"></script>
<script>
    console.log(layui);
    layui.use(['layer','jquery'], function () {
        var $ = layui.jquery;
        var layer = layui.layer;
// 在JavaScript的事件处理函数中,当你定义了形参(如e或event),即使在调用该函数时没有直接传递实参,
// 浏览器仍会自动为你传递一个事件对象作为实参。这是因为当事件发生时,浏览器或JavaScript运行环境负责
//创建一个表示该事件的对象,并将其作为第一个参数传递给事件处理函数。
// 在你的场景中,代码$('[type="submit"]').click(function (e) { ... })
//绑定了一个点击事件处理器到所有类型为submit的按钮上。当这些按钮被点击时,jQuery确保了对应的事件对象
//(包含有关事件的所有信息)被自动传递给这个匿名函数,即使你在函数定义中没有显式地在点击事件触发时传递任何参数。
// 因此,当你在函数内部使用e.preventDefault();时,实际上是访问了这个由浏览器自动提供的事件对象,并调用了它的
// preventDefault方法,从而阻止了表单的默认提交行为。这就是为什么即便没有显式传递实参,你仍然能够阻止表单提交的原因。
        $('[type="submit"]').click(function (e) { 
            e.preventDefault();
            console.log('成功');
            $.ajax({
                type: "post",
                url: "/apiadmin",
                data: "data",
                dataType: "json",
                success: function (response) {
                    if (response.code == 0){
                        layer.msg(response.msg, {icon: 6}); 
                    }else{
                        layer.msg(response.msg, {icon: 2}); 
                    }
                }
            });
        });  
    });          
</script>

</html>

fetch实例

<!DOCTYPE html>
<html lang="en">
  
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>用户登录</title>
    <link rel="stylesheet" href="/static/admin/css/layui.css">
  </head>
  
  <body>
    <div class="continar">
      <div class="login">
        <form method="post" action="/apiadmin">
          <div class="title">
            <h1>管理登录</h1>
          </div>
          <hr size="2px" width="100%" color="black">
          <div class="body">
            <div class="input">
              <label for="">用户登录</label>
              <input type="text" name="username">
            </div>
            <div class="input">
              <label for="">用户密码</label>
              <input type="password" name="password">
            </div>
            <div class="input">
              <input type="submit" name="提交">
            </div>
          </div>
        </form>
      </div>
    </div>
  </body>
  <script src="/static/admin/js/layui.js">
  </script>
  <script>console.log(layui);
    layui.use(['layer', 'jquery'],
    function() {
      var $ = layui.jquery;
      var layer = layui.layer;
      $('[type="submit"]').click(function(e) {
        e.preventDefault();
        fetch("/index/testapi" {
          herders: {
            'Accept': 'application/json'
          }
        }).then(res = >res.json()).then(res = >{
          console.log('res', res)
        })

      });
    });</script>

</html>

后端thinkphp接口

<?php
//定义命名空间
namespace app\controller;
//使用命名空间
use think\Request;
use \think\facade\Db;

function success($msg,$data){
    return json(['code'=>0,'msg'=>$msg,'data'=>$data]);
}
function error($msg,$data){
    return json(['code'=>1,'msg'=>$msg,'data'=>$data]);
}
class ApiAdmin
{
  
    public function index(Request $request,)
    {
        return error('密码错误',[]);
    }
}

错误的实例

注意ajax的请求头就是json,而fetch如果未定义的话则是text/html

fetch错误实例

return json_encode() fetch可以正常显示,但会返回整个页面,而ajax接收到的数据则是被转移后的json

<!DOCTYPE html>
<html lang="en">
  
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>用户登录</title>
    <link rel="stylesheet" href="/static/admin/css/layui.css">
  </head>
  
  <body>
    <div class="continar">
      <div class="login">
        <form method="post" action="/apiadmin">
          <div class="title">
            <h1>管理登录</h1>
          </div>
          <hr size="2px" width="100%" color="black">
          <div class="body">
            <div class="input">
              <label for="">用户登录</label>
              <input type="text" name="username">
            </div>
            <div class="input">
              <label for="">用户密码</label>
              <input type="password" name="password">
            </div>
            <div class="input">
              <input type="submit" name="提交">
            </div>
          </div>
        </form>
      </div>
    </div>
  </body>
  <script src="/static/admin/js/layui.js">
  </script>
  <script>console.log(layui);
    layui.use(['layer', 'jquery'],
    function() {
      var $ = layui.jquery;
      var layer = layui.layer;
      $('[type="submit"]').click(function(e) {
        e.preventDefault();
        fetch("/index/testapi" )
        .then(res = >res.json())
         .then(res = >{
          console.log('res', res)
        })

      });
    });</script>

</html>

fetch正确实例[如果后端返回数组或者json]

<!DOCTYPE html>
<html lang="en">
  
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>用户登录</title>
    <link rel="stylesheet" href="/static/admin/css/layui.css">
  </head>
  
  <body>
    <div class="continar">
      <div class="login">
        <form method="post" action="/apiadmin">
          <div class="title">
            <h1>管理登录</h1>
          </div>
          <hr size="2px" width="100%" color="black">
          <div class="body">
            <div class="input">
              <label for="">用户登录</label>
              <input type="text" name="username">
            </div>
            <div class="input">
              <label for="">用户密码</label>
              <input type="password" name="password">
            </div>
            <div class="input">
              <input type="submit" name="提交">
            </div>
          </div>
        </form>
      </div>
    </div>
  </body>
  <script src="/static/admin/js/layui.js">
  </script>
  <script>console.log(layui);
    layui.use(['layer', 'jquery'],
    function() {
      var $ = layui.jquery;
      var layer = layui.layer;
      $('[type="submit"]').click(function(e) {
        e.preventDefault();
        fetch("/index/testapi" {
           //如果后端返回数组,这里不添加herders,则会报错提示不能返回数组
          herders: {
            'Accept': 'application/json'
          }
        }).then(res = >res.json()).then(res = >{
          console.log('res', res)
        })

      });
    });</script>

</html>

详见thinkphp6+layui学生管理系统实战课_哔哩哔哩_bilibili第三节


评论