在请求流程中,请求与响应构成了应用与客户端交互的核心纽带 —— 请求负责捕获并解析客户端传递的各类数据(如参数、头信息、请求方式等),响应则承担着将处理结果以合适形式(如页面、JSON、文件等)返回给客户端的重任,是完成一次完整交互的关键闭环。本篇文章将记录 ThinkPHP 请求与响应的学习过程。
一、请求
1、请求对象
当前的请求对象由 think\Request 类负责,该类不需要单独实例化调用,通常使用依赖注入即可。在其它场合则可以使用 think\facade\Request 静态类操作。
在项目里面应该使用 app\Request 对象,该对象继承了系统的 think\Request 对象,但可以增加自定义方法或者覆盖已有方法。
继承 app\BaseController 基础控制器类可以直接使用 request 属性调用 think\Request 对象实例。
当然,继承基础控制器类并不是必须的,接下来说明不继承基础控制器类如何使用请求对象。
1.1、构造方法注入
只需要在构造方法的参数中声明 Request 对象参数就可以在构造方法中使用 Request 对象了。例如:
<?php
namespace app\controller;
use think\Request;
class Index
{
// 在类中声明 Request 实例
protected $request;
/**
* 构造方法,通过向构造方法中传入 Request 对象完成注入
* @param Request $request
*/
public function __construct(Request $request)
{
// 将注入的 Request 对象赋值给当前类中的 $request
$this->request = $request;
}
public function index()
{
return $this->request->param('name');
}
}
1.2、操作方法注入
Request 对象可以通过构造方法注入,同样的,也可以通过普通方法进行注入。注入的方式是一样的,只需要在需要注入 Request 对象的方法上声明该参数就可以了。例如:
<?php
namespace app\controller;
use think\Request;
class Index
{
public function index(Request $request)
{
return $request->param('name');
}
}
无论是否继承系统的控制器基类,都可以使用操作方法注入。
1.3、静态调用
除了使用依赖注入的方式使用 Request,也可以通过 Facade 机制来静态调用请求对象的方法(注意 use 引入的类库区别)。
示例
<?php
namespace app\controller;
use think\facade\Request;
class Index
{
public function index()
{
return Request::param('name');
}
}
该方法也同样适用于依赖注入无法使用的场合。
1.4、助手函数
为了简化调用,系统还提供了 request 助手函数,可以在任何需要的时候直接调用当前请求对象。
示例
<?php
namespace app\controller;
class Index
{
public function index()
{
return request()->param('name');
}
}
1.5、自定义请求对象
可以在项目里面自定义 Request 对象,修改已有的方法或者增加新的方法,默认已经在项目里准备了 app\Request 类,只需要直接修改该类就可以为你的项目单独自定义请求对象。
2、请求信息
Request 对象支持获取当前的请求信息,包括:
|
方法 |
含义 |
|
host |
当前访问域名或者IP |
|
scheme |
当前访问协议 |
|
port |
当前访问的端口 |
|
remotePort |
当前请求的REMOTE_PORT |
|
protocol |
当前请求的SERVER_PROTOCOL |
|
contentType |
当前请求的CONTENT_TYPE |
|
domain |
当前包含协议的域名 |
|
subDomain |
当前访问的子域名 |
|
panDomain |
当前访问的泛域名 |
|
rootDomain |
当前访问的根域名 |
|
url |
当前完整URL |
|
baseUrl |
当前URL(不含QUERY_STRING) |
|
query |
当前请求的QUERY_STRING参数 |
|
baseFile |
当前执行的文件 |
|
root |
URL访问根地址 |
|
rootUrl |
URL访问根目录 |
|
pathinfo |
当前请求URL的pathinfo信息(含URL后缀) |
|
ext |
当前URL的访问后缀 |
|
time |
获取当前请求的时间 |
|
type |
当前请求的资源类型 |
|
method |
当前请求类型 |
|
rule |
当前请求的路由对象实例 |
对于上面的这些请求方法,在调用时无需任何参数,但某些方法可以传入 true 参数,表示获取带域名的完整地址,例如:
use think\facade\Request;
// 获取完整URL地址 不带域名
Request::url();
// 获取完整URL地址 包含域名
Request::url(true);
// 获取当前URL(不含QUERY_STRING) 不带域名
Request::baseFile();
// 获取当前URL(不含QUERY_STRING) 包含域名
Request::baseFile(true);
// 获取URL访问根地址 不带域名
Request::root();
// 获取URL访问根地址 包含域名
Request::root(true);
2.1、获取当前控制器/操作
可以通过请求对象获取当前请求的控制器/操作名。
|
方法 |
含义 |
|
controller |
当前请求的控制器名 |
|
action |
当前请求的操作名 |
示例
// 获取当前控制器,返回的是控制器的驼峰形式(首字母大写),和控制器类名保持一致(不含后缀)。
Request::controller();
// 获取当前操作,返回的是当前操作方法的实际名称。
Request::action();
3、输入变量
可以通过 Request 对象完成全局输入变量的检测、获取和安全过滤,包括 $_GET、$_POST、$_REQUEST、$_SERVER、$_SESSION、$_COOKIE、$_ENV 等系统变量,以及文件上传信息。
3.1、检测变量是否设置
has(变量名, 请求类型) 方法来检测一个变量参数是否设置。设置返回 true,未设置返回 false。
Request::has('id','get'); // GET 请求中是否设置 id 变量
Request::has('name','post'); // POST 请求中是否设置 name 变量
变量检测可以支持所有支持的系统变量,包括:get/post/put/request/cookie/server/session/env/file。
3.2、变量获取
变量获取使用 \think\Request 类的如下方法:
变量类型方法('变量名/变量修饰符', '默认值', '过滤方法');
变量类型方法包括:
|
方法 |
描述 |
|
param |
获取当前请求的变量 |
|
get |
获取 $_GET 变量 |
|
post |
获取 $_POST 变量 |
|
put |
获取 PUT 变量 |
|
delete |
获取 DELETE 变量 |
|
session |
获取 SESSION 变量 |
|
cookie |
获取 $_COOKIE 变量 |
|
request |
获取 $_REQUEST 变量 |
|
server |
获取 $_SERVER 变量 |
|
env |
获取 $_ENV 变量 |
|
route |
获取 路由(包括PATHINFO) 变量 |
|
middleware |
获取 中间件赋值/传递的变量 |
|
file |
获取 $_FILES 变量 |
|
all |
获取包括 $_FILES 变量在内的请求变量,相当于param+file |
PARAM 类型变量是框架提供的用于自动识别当前请求的一种变量获取方式,是系统推荐的获取请求参数的方法,用法如下:
// 获取当前请求的 name 变量
Request::param('name');
// 获取当前请求的所有变量(经过过滤)
Request::param();
// 获取当前请求未经过滤的所有变量
Request::param(false);
// 获取部分变量
Request::param(['name', 'email']);
param 方法会把当前请求类型的参数和 GET 请求合并。
其它的输入变量获取方法和 param 方法用法基本一致。
3.3、变量修饰符
支持对变量使用修饰符功能,可以一定程度上简单过滤变量。
Request::变量类型('变量名/修饰符');
支持的变量修饰符有:
|
修饰符 |
作用 |
|
s |
强制转换为字符串类型 |
|
d |
强制转换为整型类型 |
|
b |
强制转换为布尔类型 |
|
a |
强制转换为数组类型 |
|
f |
强制转换为浮点类型 |
示例
Request::get('id/d'); // 变量 id 为整型
Request::post('name/s'); // 变量 name 为字符串
Request::post('ids/a'); // 变量 ids 为数组
4、请求类型
4.1、获取请求类型
在有些情况下,我们需要判断当前操作的请求类型是GET、POST、PUT、DELETE或者HEAD,一方面可以针对请求类型作出不同的逻辑处理,另外一方面有些情况下面需要验证安全性,过滤不安全的请求。
请求对象 Request 类提供了下列方法来获取或判断当前请求类型:
|
用途 |
方法 |
|
获取当前请求类型 |
method |
|
判断是否GET请求 |
isGet |
|
判断是否POST请求 |
isPost |
|
判断是否PUT请求 |
isPut |
|
判断是否DELETE请求 |
isDelete |
|
判断是否AJAX请求 |
isAjax |
|
判断是否PJAX请求 |
isPjax |
|
判断是否JSON请求 |
isJson |
|
判断是否手机访问 |
isMobile |
|
判断是否HEAD请求 |
isHead |
|
判断是否PATCH请求 |
isPatch |
|
判断是否OPTIONS请求 |
isOptions |
|
判断是否为CLI执行 |
isCli |
|
判断是否为CGI模式 |
isCgi |
method 方法返回的请求类型始终是大写,这些方法都不需要传入任何参数。
4.2、请求类型伪装
ThinkPHP 支持请求类型伪装,可以在POST表单里面提交 _method 变量,传入需要伪装的请求类型,例如:
<form method="post" action="">
<input type="text" name="name" value="Hello">
<input type="hidden" name="_method" value="PUT" >
<input type="submit" value="提交">
</form>
提交后的请求类型会被系统识别为 PUT 请求。
可以设置为任何合法的请求类型,包括GET、POST、PUT和DELETE等,但伪装变量 _method 只能通过 POST 请求进行提交。
5、HTTP头信息
可以使用 Request 对象的 header 方法获取当前请求的HTTP请求头信息。
示例
// 获取的信息为数组,通过信息头名称获取值
$info = Request::header();
echo $info['accept'];
echo $info['accept-encoding'];
echo $info['user-agent'];
// 也可以直接获取某个请求头信息
$agent = Request::header('user-agent');
HTTP 请求头信息的名称不区分大小写,并且 _ 会自动转换为 - 。
6、参数绑定
参数绑定是把当前请求的变量作为操作方法的参数直接传入,参数绑定并不区分请求类型。
参数绑定方式默认是按照变量名进行绑定。例如,我们给 Blog 控制器定义了 read 方法,read 方法需要指定年份(year)和月份(month)两个参数,那么我们可以这样定义:
<?php
namespace app\controller;
class Blog
{
public function read($year, $month='01')
{
return 'year=' . $year . '&month=' . $month;
}
}
URL的访问地址是:
http://serverName/blog/read/year/2025/month/12
或者
http://serverName/blog/read?year=2021&month=02
按照变量名进行参数绑定的参数必须和URL中传入的变量名称一致,但是参数顺序不需要。
二、响应
ThinkPHP的 Response 响应对象由 think\Response 类或者子类完成,ThinkPHP的响应输出是自动的,最终会调用 Response 对象的 send 方法完成输出。
1、响应输出
大多数情况下,我们不需要关注 Response 对象本身,只需要在控制器的操作方法中返回数据即可。最简单的响应输出是直接在控制器操作方法中返回一个字符串,例如:
<?php
namespace app\controller;
class Index
{
public function hello($name='thinkphp')
{
return 'Hello,' . $name . '!';
}
}
默认是输出 html。如果发起一个 JSON 请求的话,输出就会自动使用 JSON 格式响应输出。
为了规范和清晰起见,最佳的方式是在控制器最后明确输出类型。默认支持的输出类型包括:
|
输出类型 |
快捷方法 |
对应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 |
|
附件下载 |
download |
\think\response\File |
2、响应参数
Response 对象提供了一系列方法用于设置响应参数,包括设置输出内容、状态码及 header 信息等,并且支持链式调用以及多次调用。
2.1、设置数据
Response 基类提供的 data 方法用于设置响应数据。
示例
response()->data($data);
json()->data($data);
需要注意的是 data 方法设置的只是原始数据,并不一定是最终的输出数据,最终的响应输出数据是会根据当前的 Response 响应类型做自动转换。例如:
json()->data($data);
最终的输出数据就是 json_encode($data) 转换后的数据。
2.2、设置状态码
Response 基类提供的 code 方法用于设置响应的状态码,但一般情况下,都是在调用助手函数的时候直接传入状态码。
示例
json($data, 201);
view($data, 401);
// 或者在后面链式调用code方法:
json($data)->code(201);
除了 redirect 函数的默认返回状态码是302之外,其它方法没有指定状态码都是返回200状态码。
2.3、设置头信息
Response 基类提供的 header 方法用于设置响应的头信息。
示例
json($data)->code(201)->header([
'Cache-control' => 'no-cache,must-revalidate'
]);
3、重定向
使用 redirect(URL) 助手函数进行重定向。
示例
<?php
namespace app\controller;
class Index
{
public function hello()
{
return redirect('http://www.baidu.com');
}
}
还可以支持使用 with 方法附加 Session 闪存数据重定向。
<?php
namespace app\controller;
class Index
{
public function index()
{
return redirect('/hello')->with('name','thinkphp');
}
public function hello()
{
$name = session('name');
return 'hello,'.$name.'!';
}
}
需要说明的是,Session 闪存的数据仅在下一次请求有效,再次访问重定向地址的时候无效。
4、文件下载
支持文件下载功能,可以更简单的读取文件进行下载操作,支持直接下载输出内容。
助手函数 download(要下载的文件, 显示的文件名, 是否为内容, 有效期(秒)) 用于文件下载。
示例
public function download($year, $month='01')
{
return download('image.jpg', 'my.jpg');
}
访问 download 操作就会下载命名为 my.jpg 的图像文件。
下载文件的路径是服务器路径而不是URL路径,如果要下载的文件不存在,系统会抛出异常。
支持设置是否强制下载,例如需要打开图像文件而不是浏览器下载的话,可以使用 force 方法:
public function download()
{
// force()方法:是否强制下载
return download('image.jpg', 'my.jpg')->force(false);
}
除了 force 方法外,还支持下面的方法:
|
方法 |
描述 |
|
name |
命名下载文件 |
|
expire |
下载有效期 |
|
isContent |
是否为内容下载 |
|
mimeType |
设置文件的mimeType类型 |
|
force |
是否强制下载 |
938

被折叠的 条评论
为什么被折叠?



