ThinkPhp5下使用restful风格路由导致跨域put请求失效解决办法
2017-07-29 10:06
639 查看
今天写代码的时候,碰到ajax发起put请求失败的问题,碰到这个情况的时候时候我也一脸懵逼,不过还好,费了不少功夫终于解决。
使用的官方资源控制器生成的restful控制器
在Route.php下路由
生成后的user类:
上面输出是为了api请求时有返回值,方便调试
ajax:
第一次请求:
报了一个404错误。控制台输出:XMLHttpRequest cannot load…..。
ajax跨域导致的错误,解决方式:
1、使用jsonp方式
2、服务器准许跨域
使用jsonp的方式调用的话路由会当做一个get请求 然后调用read()方法。可以去修改路由
这里使用第二种:服务器准许跨域:
在index.php头部添加响应信息:
这个时候post请求已经是正常了,但是put请求还是报错,并提示无法跨域
这个时候注意到了一点,ajax是发起的put请求。为什么浏览器提交的是OPTIONS请求?这点很奇怪,第一次碰到。百度options请求后大概是这么个意思
浏览器在发起复杂请求(如跨域)之前会先发起一个options的请求来嗅探服务器是否支持改请求或方法等
有复杂请求就有简单请求:
如get、post,就属于简单请求。
那么,我们就有一个大胆的猜想:浏览器在发起options请求嗅探的时候,被tp检测到,并没有检测到这个路由。而user也不是具体的方法,从而导致返回404。浏览器在接收到是404后就不会在发起put请求。
结果测试,这个猜想是正确的。查看框架的Route.php源码。是把options请求当做所有请求中的一种,并没有做单独处理。(这话怎么都感觉有点不对,不要纠结这里)
这个方法也行的通,但是要修改框架源码了,不甘心,难道就没有不修改框架源码,又简单的方法了吗?经过摸索后还真有。看下面这种方法。
在index.php头部添加下面代码:
额?这么简单? 就这么简单,我们主要让上面的请求头能够正常返回就行。浏览器只有正常返回的情况下才会发出put请求。
有两次请求,第一次请求时嗅探是否准许,第二次才是我们的put请求。
但是这个会造成2次请求,能不能在优化下,变成一次请求。
在config.php里设置
然后ajax代码:
嗯,达到了预期的效果。和第二种方法相比,各有特点。
自学注定不是一帆风顺的,多看文档,多思考,多搜索!
问题
通过官方资源控制器生成的restful控制器,在路由后浏览器进行ajax跨域put请求,导致请求失败。get和post请求正常,postman测试put请求正常。分析
这个问题相信很多人也碰到,在官方的github上面有人提到过这个问题,但没有具体的解决方法。先看下代码把。tp版本是最新版本5.0.10使用的官方资源控制器生成的restful控制器
php think make:controller app\index\controller\user
在Route.php下路由
use think\Route; Route::resource('user', 'index/User');
生成后的user类:
<?php namespace app\index\controller; use think\Controller; use think\Request; class User extends Controller { public function index() { // 默认get echo 'index'; } public function create() { // echo 'create'; } public function save(Request $request) { // echo 'save()'; } public function read($id) { // echo 'read'; } public function edit($id) { // echo 'edit'; } public function update(Request $request, $id) { // echo 'put - update()'; } public function delete($id) { // echo 'delete'; } }
上面输出是为了api请求时有返回值,方便调试
ajax:
$.ajax({ url: 'http://localhost:9096/think/public/index.php/user/2', type: 'put', dataType: 'text', success: function (data) { console.log(data); } });
第一次请求:
报了一个404错误。控制台输出:XMLHttpRequest cannot load…..。
ajax跨域导致的错误,解决方式:
1、使用jsonp方式
2、服务器准许跨域
使用jsonp的方式调用的话路由会当做一个get请求 然后调用read()方法。可以去修改路由
这里使用第二种:服务器准许跨域:
在index.php头部添加响应信息:
header("Access-Control-Allow-Origin: * "); header("Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE");
这个时候post请求已经是正常了,但是put请求还是报错,并提示无法跨域
这个时候注意到了一点,ajax是发起的put请求。为什么浏览器提交的是OPTIONS请求?这点很奇怪,第一次碰到。百度options请求后大概是这么个意思
浏览器在发起复杂请求(如跨域)之前会先发起一个options的请求来嗅探服务器是否支持改请求或方法等
有复杂请求就有简单请求:
如get、post,就属于简单请求。
那么,我们就有一个大胆的猜想:浏览器在发起options请求嗅探的时候,被tp检测到,并没有检测到这个路由。而user也不是具体的方法,从而导致返回404。浏览器在接收到是404后就不会在发起put请求。
结果测试,这个猜想是正确的。查看框架的Route.php源码。是把options请求当做所有请求中的一种,并没有做单独处理。(这话怎么都感觉有点不对,不要纠结这里)
解决办法
1、修改框架源码或路由规则
框架的Route.php --- // REST路由操作方法定义 private static $rest = [ 'index' => ['get', '', 'index'], 'create' => ['get', '/create', 'create'], 'edit' => ['get', '/:id/edit', 'edit'], 'read' => ['get', '/:id', 'read'], 'save' => ['post', '', 'save'], // 修改为options方法 'update' => ['options', '/:id/put', 'update'], 'delete' => ['options', '/:id/delete', 'delete'], ];
这个方法也行的通,但是要修改框架源码了,不甘心,难道就没有不修改框架源码,又简单的方法了吗?经过摸索后还真有。看下面这种方法。
2、单独处理options请求
浏览器发起options请求嗅探后被框架返回404,那我们就单独处理这个请求,使他能正常返回;在index.php头部添加下面代码:
// 准许跨域请求。
header("Access-Control-Allow-Origin: * "); header("Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE");
/**
* 浏览器第一次在处理复杂请求的时候会先发起OPTIONS请求。路由在处理请求的时候会导致PUT请求失败。
* 在检测到option请求的时候就停止继续执行
*/
if($_SERVER['REQUEST_METHOD'] == 'OPTIONS'){
exit;
}
额?这么简单? 就这么简单,我们主要让上面的请求头能够正常返回就行。浏览器只有正常返回的情况下才会发出put请求。
有两次请求,第一次请求时嗅探是否准许,第二次才是我们的put请求。
但是这个会造成2次请求,能不能在优化下,变成一次请求。
3、使用请求伪装
通过查阅手册发现可以设置请求伪装的方式达到同样的效果。文档地址在config.php里设置
'var_method => '_method',
然后ajax代码:
$.ajax({ url: 'http://localhost:9096/think/public/index.php/user/2', type: 'post', data:{ _method:'PUT' }, dataType: 'text', success: function (data) { console.log(data); } });
嗯,达到了预期的效果。和第二种方法相比,各有特点。
自学注定不是一帆风顺的,多看文档,多思考,多搜索!
相关文章推荐
- 资料汇总--Ajax中Put和Delete请求传递参数无效的解决方法(Restful风格)【转】
- AJAX 跨域请求的解决办法:使用 JSONP获取JSON数据
- 解决Ajax中Restful风格PUT和DELETE请求传递参数无效
- Ajax中Put和Delete请求传递参数无效的解决方法(Restful风格)
- 使用jquery框架导致js功能失效解决办法
- DISCUZ 使用 JQ做效果导致DIY失效的解决办法
- Ajax中Put和Delete请求传递参数无效的解决方法(Restful风格
- vue前后端分离使用fetch 跨域请求时 session失效问题解决
- Spring MVC使用RESTful风格的PUT请求
- asp.net中使用 UpdatePanel 回传导致js 失效解决办法
- AJAX 跨域请求的解决办法:使用 JSONP获取JSON数据
- js_html_input中autocomplete="off"在chrom中失效的解决办法 使用JS模拟锚点跳转 js如何获取url参数 C#模拟httpwebrequest请求_向服务器模拟cookie发送 实习期学到的技术(一) LinqPad的变量比较功能 ASP.NET EF 使用LinqPad 快速学习Linq
- 几个问题(十一)-------ajax是否能跨域请求,解决的办法
- 使用了与请求的协议不兼容的地址的解决办法。
- QSqlDatabase 使用小结,解决部分数据库操作导致程序崩溃的办法
- 解决ArrayCollection中使用for each删除指定项的失效的办法
- 使用过多的窗体导致创建句柄失败的解决办法
- QT中使用槽函数来关闭窗口,导致内存泄露的问题以及解决办法
- 使用PL/SQL Developer 报错:ORA-01460 :转换请求无法实现或不合理 解决办法!!!
- Linux(RHEL5.4)通过Ftp put命令上传导致文件损坏的解决办法