Yii2.0 探究五:基于Yii2.0框架的Restful Api的对接以及跨域解决
基于Yii2.0框架的Restful Api的对接以及跨域解决;
2.新建api模块,专门用来存放api相关,并配置响应格式为json而不是xml;
3.改造请求错误提示为Json格式,而非html;
4.测试调试请求;
5.前端进行接收,这部分我们说下前端ajax如何跨域做出请求;
准备:
1.新建news表用来展示(也可以用命令行migration去建表):
2.api的请求工具:chrome中建议安装postman、firefox中安装HttpRequest,其他浏览器自行解决;
3.Json的查看工具:chrome中建议安装JSONView,会显示格式化的json,firefox中安装jsonformater,其他浏览器自行解决;
3.开启伪静态rewrite、并且配置api的二级域名为api.news.com格式,绑定在api/web下面;
1.copy一份frontend或backend目录下的文件重命名为api放置在同级下作为api的内容,在common>bootstrap.php文件中依赖注入声明api模块:
Yii::setAlias("@api",dirname(dirname(__DIR__))."/api");
2.在api下新建v1、v2作为我们不同版本的内容、并在里面新建controllers、models、views部分,并分别在v1、v2下新建Module.php声明命名空间;
3.api文件夹相关命名空间可自行修改,这里我们要对配置文件作出修改:
4.新建api>modules>v1>controllers>NewsController控制器用来响应,并重写behaviors响应为json:
5.新建model在api>modules>v1>modles>News.php,可采用gii生成;
以上就是api模块建立的过程;
1.在common>controllers>ErrorAction.php去重写action错误的提示;
这里我们做出错误请求,api.news.com/v3你会发现,提示Json数据为
{status: "error", code: 404, msg: "页面未找到。"}
这在api请求错误时很有帮助;
1.在数据表news中插入数据
2.在postman中我们输入http://api.news.com/v1/news会显示出news的数据;
3.格式:一般Restful Api的格式是固定的;当然也可以去重写;
GET http://api.news.com/v1/news 列出所有新闻
GET http://api.news.com/v1/news/1 列出id为1的新闻
POST http://api.news.com/v1/news 新建新闻
DELETE http://api.news.com/v1/news/1 删除id为1的新闻
PUT/PATCH http://api.news.com/v1/news/1 修改id为1的新闻
我们可以在postman中输入以上url做测试,其他方式例如OPTIONS、HEAD可寻找资料或查看手册;
以上我们就搭建完成了Restful api的接口;
前面:前端所有部分都通过jquery来做ajax请求;
事实上我们只需要一个button按钮来测试我们所得到的数据;
在frontend.news.com中新建一个action并render一个视图我们用来测试
当你在frontend.news.com用ajax去请求我们api.news.com的api接口时候,你会发现:请求失败,并报错,原因是跨域,浏览器做出了限制;
也就是说我们域名相同、端口相同、协议相同才不算做是跨域,那么该怎么办。。。。。。。。。。
不用担心,自有跨域的解决办法、这里介绍两种,其他可google解决:
1.JsonP跨域解决:ajax中设定datatype的类型为jsonp就行了,很简单;
优点是:对于一些古老的浏览器很高的支持;例如万恶的ie。。。
缺点是:只能发出GET请求,其他method无法操作,例如POST、DELETE等
2.cros同源策略:设置方式,只要在action中设置header头部即可,也是最简单、最常用的一种(如果不考虑ie的话)
优点:操作方便,只需添加header;支持新兴浏览器;所有方式都可采用:例如GET、POST、DELETE、PUT、PATCH、OPTIONS等
Access-Control-Allow-Origin:*或者建立信任的url,例如:Access-control-Origin:http://frontend.news.com;
Access-Control-Allow-Methods:*允许操作的方法为所有;
缺点:对ie的支持不好,兼容性IE10以前的都不能用。
The END
在yii2.0框架中集成了restful api的部分,封装在yii est下,我们要做的工作有:
1.apache或nginx中开启rewrite伪静态模式(可自行搜索)
2.新建api模块,专门用来存放api相关,并配置响应格式为json而不是xml;
3.改造请求错误提示为Json格式,而非html;
4.测试调试请求;
5.前端进行接收,这部分我们说下前端ajax如何跨域做出请求;
准备:
1.新建news表用来展示(也可以用命令行migration去建表):
DROP TABLE IF EXISTS `news`; CREATE TABLE IF NOT EXISTS `news` ( `id` int(11) NOT NULL AUTO_INCREMENT, `title` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `time` int(11) NOT NULL DEFAULT "0", PRIMARY KEY (`id`), UNIQUE KEY `title` (`title`) ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
2.api的请求工具:chrome中建议安装postman、firefox中安装HttpRequest,其他浏览器自行解决;
3.Json的查看工具:chrome中建议安装JSONView,会显示格式化的json,firefox中安装jsonformater,其他浏览器自行解决;
3.开启伪静态rewrite、并且配置api的二级域名为api.news.com格式,绑定在api/web下面;
1.copy一份frontend或backend目录下的文件重命名为api放置在同级下作为api的内容,在common>bootstrap.php文件中依赖注入声明api模块:
Yii::setAlias("@api",dirname(dirname(__DIR__))."/api");
2.在api下新建v1、v2作为我们不同版本的内容、并在里面新建controllers、models、views部分,并分别在v1、v2下新建Module.php声明命名空间;
<?php /** * @see https://github.com/craftsmann. * @author craftsmann <m13993334619@163.com> */ namespace apimodulesv1; class Module extends yiiaseModule { public $controllerNamespace = "apimodulesv1controllers"; public function init() { parent::init(); // TODO: Change the autogenerated stub } } ?>
3.api文件夹相关命名空间可自行修改,这里我们要对配置文件作出修改:
<?php $params = array_merge( require(__DIR__ . "/../../common/config/params.php"), require(__DIR__ . "/../../common/config/params-local.php"), require(__DIR__ . "/params.php"), require(__DIR__ . "/params-local.php") ); return [ "id" => "app-api", "basePath" => dirname(__DIR__), "bootstrap" => ["log"], "language" =>"zh-CN", "controllerNamespace" => "apicontrollers", "modules"=>[ "v1"=>["class"=>"apimodulesv1Module"], "v2"=>["class"=>"apimodulesv2Module"], ], "components" => [ "user" => [ "identityClass" => "commonmodelsUser", "enableAutoLogin" => false, "enableSession" =>false, "loginUrl" =>null, ], "log" => [ "traceLevel" => YII_DEBUG ? 3 : 0, "targets" => [ [ "class" => "yiilogFileTarget", "levels" => ["error", "warning"], ], ], ], "errorHandler" => [ "errorAction" => "site/error", ], "urlManager" => [ "enablePrettyUrl" => true, "enableStrictParsing" => true, // 是否执行严格的url解析 "showScriptName" => false, "rules" => [ [ "class"=>"yii estUrlRule", "controller"=>["v1/users","v1/news"], ] ], ], ], "params" => $params, ]; ?>
4.新建api>modules>v1>controllers>NewsController控制器用来响应,并重写behaviors响应为json:
<?php /** * @see https://github.com/craftsmann. * @author craftsmann <m13993334619@163.com> */ namespace apimodulesv1controllers; use yii estActiveController; class NewsController extends ActiveController { //响应数据为 public $modelClass="apimodulesv1modelsGoods"; public function behaviors() { $behaviors = parent::behaviors(); $behaviors["contentNegotiator"]["formats"] = ["application/json" => yiiwebResponse::FORMAT_JSON]; return $behaviors; } ?>
5.新建model在api>modules>v1>modles>News.php,可采用gii生成;
以上就是api模块建立的过程;
1.在common>controllers>ErrorAction.php去重写action错误的提示;
?php /** * @see https://github.com/craftsmann. * @author craftsmann <m13993334619@163.com> */ namespace commoncontrollers; use Yii; use yiiaseException; use yiiaseUserException; use yiiwebHttpException; class ErrorAction extends yiiwebErrorAction { public function run() { if (($exception = Yii::$app->getErrorHandler()->exception) === null) { // action has been invoked not from error handler, but by direct route, so we display "404 Not Found" $exception = new HttpException(404, Yii::t("yii", "Page not found.")); } if ($exception instanceof HttpException) { $code = $exception->statusCode; } else { $code = $exception->getCode(); } if ($exception instanceof Exception) { $name = $exception->getName(); } else { $name = $this->defaultName ?: Yii::t("yii", "Error"); } if ($exception instanceof UserException) { $message = $exception->getMessage(); } else { $message = $this->defaultMessage ?: Yii::t("yii", "An internal server error occurred."); } if (Yii::$app->getRequest()->getIsAjax()) { echo json_encode( [ "name"=>$name, "msg" =>$message ] ); } else { echo json_encode( [ "status"=>"error", "code"=>$code, "msg" =>$message, ] ); } } }
这里我们做出错误请求,api.news.com/v3你会发现,提示Json数据为
{status: "error", code: 404, msg: "页面未找到。"}
这在api请求错误时很有帮助;
1.在数据表news中插入数据
2.在postman中我们输入http://api.news.com/v1/news会显示出news的数据;
3.格式:一般Restful Api的格式是固定的;当然也可以去重写;
GET http://api.news.com/v1/news 列出所有新闻
GET http://api.news.com/v1/news/1 列出id为1的新闻
POST http://api.news.com/v1/news 新建新闻
DELETE http://api.news.com/v1/news/1 删除id为1的新闻
PUT/PATCH http://api.news.com/v1/news/1 修改id为1的新闻
我们可以在postman中输入以上url做测试,其他方式例如OPTIONS、HEAD可寻找资料或查看手册;
以上我们就搭建完成了Restful api的接口;
前面:前端所有部分都通过jquery来做ajax请求;
事实上我们只需要一个button按钮来测试我们所得到的数据;
在frontend.news.com中新建一个action并render一个视图我们用来测试
<?php /** * @see https://github.com/craftsmann. * @author craftsmann <m13993334619@163.com> */ use yiiootstrapActiveForm; frontendassetsAppAsset::register($this); ?> <?php $this->beginBlock("js")?> $("#api").on("click",function(){ $.ajax({ type: "get", url: "http://api.hotel.com/v1/news/1", success: function(data){ $("#message").html("新增新闻名称:"+data.name); }, error: function(news){ $("#message").html(news.responseJSON[0].message); } }); }); <?php $this->endBlock()?> <?php $this->registerJs($this->blocks["js"],yiiwebView::POS_END);?> <div class="container"> <div class="form-group"> <?= yiihelpersHtml::Button("提交",["class"=>"btn btn-default","id"=>"api"])?> </div> <a id="message"></a> </div>
当你在frontend.news.com用ajax去请求我们api.news.com的api接口时候,你会发现:请求失败,并报错,原因是跨域,浏览器做出了限制;
也就是说我们域名相同、端口相同、协议相同才不算做是跨域,那么该怎么办。。。。。。。。。。
不用担心,自有跨域的解决办法、这里介绍两种,其他可google解决:
1.JsonP跨域解决:ajax中设定datatype的类型为jsonp就行了,很简单;
优点是:对于一些古老的浏览器很高的支持;例如万恶的ie。。。
缺点是:只能发出GET请求,其他method无法操作,例如POST、DELETE等
2.cros同源策略:设置方式,只要在action中设置header头部即可,也是最简单、最常用的一种(如果不考虑ie的话)
优点:操作方便,只需添加header;支持新兴浏览器;所有方式都可采用:例如GET、POST、DELETE、PUT、PATCH、OPTIONS等
Access-Control-Allow-Origin:*或者建立信任的url,例如:Access-control-Origin:http://frontend.news.com;
Access-Control-Allow-Methods:*允许操作的方法为所有;
缺点:对ie的支持不好,兼容性IE10以前的都不能用。
The END
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。