本讲的内容主要是如何根据不同的请求进行响应输出,主要包括:
[TOC]
> 响应(Response)对象用于动态响应客户端请求,控制发送给用户的信息。通常用于输出数据给客户端或者浏览器。
ThinkPHP5的Response响应对象由`think\Response`类或者子类完成,ThinkPHP的`App::run()`方法的返回值是一个`Response`对象实例,最终会调用`Response对象`的`send方法`完成输出。
#### 自动输出
大多数情况,我们不需要关注`Response对象`本身,只需要在控制器的操作方法中返回数据即可,系统会根据`default_return_type`和`default_ajax_return`配置决定响应输出的类型。
默认的自动响应输出会自动判断是否AJAX请求,如果是的话会自动输出default_ajax_return配置的输出类型。
~~~
<?php
namespace app\index\controller;
class Index
{
public function hello()
{
$data = ['name' => 'thinkphp', 'status' => '1'];
return $data;
}
}
~~~
由于默认是输出Html输出,所以访问页面输出结果为:
![](https://box.kancloud.cn/5d142e9055c6153345ce37194db63b11_1389x1043.png)
修改配置文件,添加:
~~~
// 默认输出类型
'default_return_type' => 'json',
~~~
再次访问的输出结果为:
![](https://box.kancloud.cn/6e388827d139006a4baaf2e7e117e1c9_1389x1043.png)
修改输出类型为xml:
~~~
// 默认输出类型
'default_return_type' => 'xml',
~~~
则输出结果变成:
![](https://box.kancloud.cn/9cdd4002d776a4460585f7fd3a544883_1389x1043.png)
> 现在明白为什么控制器的操作方法中不要直接echo输出,而要使用return返回了么。
#### 手动输出
> 在必要的时候,可以手动控制输出类型和参数(也是建议的方式),这种方式较为灵活。
例如如果需要指定json输出类型,可以使用下面的方式:
~~~
<?php
namespace app\index\controller;
use think\Response;
class Index
{
public function hello()
{
$data = ['name' => 'thinkphp', 'status' => '1'];
return Response::create($data,'json');
}
}
~~~
或者直接使用系统提供的助手函数输出json:
~~~
<?php
namespace app\index\controller;
class Index
{
public function hello()
{
$data = ['name' => 'thinkphp', 'status' => '1'];
return json($data);
}
}
~~~
使用助手函数不受配置参数设置的影响,页面输出的结果为:
~~~
{"name":"thinkphp","status":"1"}
~~~
默认的情况下发送的http状态码是200,如果需要返回其它的状态码,可以使用:
~~~
<?php
namespace app\index\controller;
class Index
{
public function hello()
{
$data = ['name' => 'thinkphp', 'status' => '1'];
return json($data, 201);
}
}
~~~
或者发送更多的响应头信息:
~~~
<?php
namespace app\index\controller;
class Index
{
public function hello()
{
$data = ['name' => 'thinkphp', 'status' => '1'];
return json($data, 201, ['Cache-control' => 'no-cache,must-revalidate']);
}
}
~~~
也支持使用下面的链式调用的方式:
~~~
<?php
namespace app\index\controller;
class Index
{
public function hello()
{
$data = ['name' => 'thinkphp', 'status' => '1'];
return json($data)->code(201)->header(['Cache-control' => 'no-cache,must-revalidate']);
}
}
~~~
默认支持的输出类型包括:
|输出类型 |快捷方法 |对应Response类|
|--|--|--|
|HTML输出 |response |\think\Response|
|渲染模板输出 |view |\think\response\View|
|JSON输出| json |\think\response\Json|
|JSONP输出| jsonp |\think\response\Jsonp|
|XML输出 |xml |\think\response\Xml|
|页面重定向 |redirect |\think\response\Redirect|
所以,同样的可以使用xml方法输出XML数据类型:
~~~
<?php
namespace app\index\controller;
class Index
{
public function hello()
{
$data = ['name' => 'thinkphp', 'status' => '1'];
return xml($data, 201);
}
}
~~~
如果你只需要输出一个html格式的内容,可以直接使用
~~~
<?php
namespace app\index\controller;
class Index
{
public function hello()
{
$data = 'Hello,ThinkPHP!';
return response($data);
}
}
~~~
每一种输出类型其实对应了一个不同的Response子类(response()函数对应的是Response基类),也可以在应用中自定义Response子类满足特殊需求的输出。
这些助手函数的返回值都是Response类或者子类的对象实例,所以后续可以调用Response基类或者当前子类的相关方法,后面我们会讲解相关方法。
关于view助手函数的详细用法我们还会在下一讲中进行更详细的讲解。
#### 设置数据
Response基类提供了data方法用于设置响应数据。
~~~
response()->data($data);
json()->data($data);
~~~
不过需要注意的是data方法设置的只是原始数据,并不一定是最终的输出数据,最终的响应输出数据是会根据当前的Response响应类型做自动转换的,例如:
~~~
json()->data($data);
~~~
最终的输出数据就是`json_encode($data)`转换后的数据。
如果要获取当前响应对象实例的实际输出数据可以使用`getContent方法`。
#### 设置状态码
Response基类提供了code方法用于设置响应数据,但大部分情况一般我们是直接在调用助手函数的时候直接传入状态码,例如:
~~~
json($data,201);
view($data,401);
~~~
或者在后面链式调用code方法是等效的:
~~~
json($data)->code(201);
~~~
除了redirect函数的默认返回状态码是302之外,其它方法没有指定状态码都是返回200状态码。
如果要获取当前响应对象实例的状态码的值,可以使用getCode方法。
#### 设置头信息
可以使用Response类的header设置响应的头信息
~~~
json($data)->code(201)->header(['Cache-control' => 'no-cache,must-revalidate']);
~~~
header方法支持两种方式设置,如果传入数组,则表示批量设置,如果传入两个参数,第一个参数表示头信息名,第二个参数表示头信息的值,例如:
~~~
// 单个设置
header('Cache-control', 'no-cache,must-revalidate');
// 批量设置
header([
'Cache-control' => 'no-cache,must-revalidate',
'Last-Modified' => gmdate('D, d M Y H:i:s') . ' GMT',
]);
~~~
除了header方法之外,Response基类还提供了常用头信息的快捷设置方法:
|方法名 |作用|
|--|--|
|lastModified |设置Last-Modified头信息|
|expires |设置Expires头信息|
|eTag |设置ETag头信息|
|cacheControl |设置Cache-control头信息|
|contentType |设置Content-Type头信息|
除非你要清楚自己在做什么,否则不要随便更改这些头信息,每个Response子类都有默认的contentType信息,一般无需设置。
你可以使用`getHeader方法`获取当前响应对象实例的头信息。
#### 设置额外参数
有些时候,响应输出需要设置一些额外的参数,例如:
在进行json输出的时候需要设置json_encode方法的额外参数,jsonp输出的时候需要设置jsonp_handler等参数,这些都可以使用options方法来进行处理,例如:
~~~
json($data)
->options('json_encode_param',JSON_PRETTY_PRINT);
~~~
也可以支持传入数组作为参数:
~~~
jsonp($data)
->options([
'var_jsonp_handler' => 'callback',
'default_jsonp_handler' => 'jsonpReturn',
'json_encode_param' => JSON_PRETTY_PRINT,
]);
~~~
#### 重定向
可以使用redirect助手函数进行重定向
~~~
<?php
namespace app\index\controller;
class Index
{
public function hello()
{
return redirect('http://www.thinkphp.cn');
}
}
~~~
redirect函数和控制器的redirect方法的参数顺序有所区别。
#### 重定向传参
如果是站内重定向的话,可以支持URL组装,有两种方式组装URL,第一种是直接使用完整地址(/打头)
~~~
redirect('/index/index/hello/name/thinkphp');
~~~
这种方式会保持原来地址不做任何转换,第二种方式是使用params方法配合,例如:
~~~
redirect('hello')->params(['name'=>'thinkphp']);
~~~
最终重定向的URL地址和前面的一样的,系统内部会自动判断并调用url(用于快速生成URL地址的助手函数)方法进行地址生成,相当于
~~~
redirect(url('hello',['name'=>'thinkphp']));
~~~
还可以支持使用with方法进行重定向隐式传值。
~~~
<?php
namespace app\index\controller;
class Index
{
public function index()
{
return redirect('hello')->with('name','thinkphp');
}
public function hello()
{
$name = session('name');
return 'hello,'.$name.'!';
}
}
~~~
从示例可以看到重定向隐式传值使用的是Session方式隐式传值,并且仅在下一次请求有效,再次访问重定向地址的时候无效。
我们访问请求
~~~
http://www.tp5.com
~~~
会输出:
![](https://box.kancloud.cn/f9a0f79e6f7b023725abad68d47ae96a_860x617.png)
但当我们第二次请求
http://www.tp5.com/index/index/hello
的时候,页面输出结果为:
![](https://box.kancloud.cn/ca06ccbe348ba4ce76a955a344acb6c1_860x617.png)
#### 记住请求地址
在很多时候,我们重定向的时候需要记住当前请求地址(为了便于跳转回来),我们可以使用`remember方法`记住重定向之前的请求地址。
下面是一个示例,我们第一次访问index操作的时候会重定向到hello操作并记住当前请求地址,然后操作完成后到restore方法,restore方法则会自动重定向到之前记住的请求地址,完成一次重定向的回归,回到原点!(再次刷新页面又可以继续执行)
~~~
<?php
namespace app\index\controller;
class Index
{
public function index()
{
// 判断session完成标记是否存在
if (session('?complete')) {
// 删除session
session('complete', null);
return '重定向完成,回到原点!';
} else {
// 记住当前地址并重定向
return redirect('hello')
->with('name', 'thinkphp')
->remember();
}
}
public function hello()
{
$name = session('name');
return 'hello,' . $name . '! <br/><a href="/index/index/restore">点击回到来源地址</a>';
}
public function restore()
{
// 设置session标记完成
session('complete', true);
// 跳回之前的来源地址
return redirect()->restore();
}
}
~~~
#### 总结
目前我们已经掌握了不同类型的响应输出以及设置,下一讲的内容是专门针对模板渲染做了更深入的讲解。