使用 Laravel 的资源路由,我设置了一个 API 来充当 React JS 应用程序的后端。我当前正在尝试访问“更新”方法。我使用 Javascript 的 fetch()
来完成此操作,因此它首先发出一个 OPTIONS
请求,然后发出 POST
请求(表单具有其中的方法欺骗,将 _method
设置为 PATCH
- 这显然不会影响初始 OPTIONS
调用)。同一个页面还通过相同的方法向同一端点发出 GET
请求,效果很好。
fetch()
调用如下。当然,这是 React,它是通过 Redux Saga 进程调用的,但实际的获取就在那里。
function postApi(values, endpoint, token) { // <-- values and endpoint are sent by the component, token is sent by a previous Saga function
return fetch(apiUrl + endpoint, { // <-- apiUrl is defined as a constant earlier in the file
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + token
},
body: JSON.stringify(
values
)
}).then(handleApiErrors)
.then(response => response.json())
.catch((error) => {throw error})
}
以及 Laravel 路线:
Route::group(['middleware' => 'auth:api'], function() {
Route::resource('users', 'UserController');
}
我遇到了一个错误,其中对 URL 的初始 OPTIONS
请求返回 404
错误,这很奇怪,因为端点显然存在,确切的几秒钟前刚刚查询了相同的端点,但我认为 Laravel 可能返回了错误的错误,并且我使用了错误的方法。在放弃并在 Postman 中发出请求之前,我做了一些挖掘和调试,试图让请求正确。事实是:它在 Postman 中工作正常。
以下是来自服务器的响应 header (请注意,允许任何访问源):
Access-Control-Allow-Origin:*
Cache-Control:no-cache, private
Connection:close
Content-Length:10
Content-Type:text/html; charset=UTF-8
Date:Thu, 21 Sep 2017 13:29:08 GMT
Server:Apache/2.4.27 (Unix) OpenSSL/1.0.2l PHP/7.0.22 mod_perl/2.0.8-dev Perl/v5.16.3
X-Powered-By:PHP/7.0.22
以下是 React JS 应用程序(收到 404 错误的应用程序)发出的请求的请求 header :
Accept:*/*
Accept-Encoding:gzip, deflate, br
Accept-Language:en-US,en;q=0.8,fr;q=0.6,ga;q=0.4
Access-Control-Request-Headers:authorization,content-type
Access-Control-Request-Method:POST
Cache-Control:no-cache
Connection:keep-alive
Host:localhost
Origin:http://localhost:3000
Pragma:no-cache
Referer:http://localhost:3000/employees/edit/13
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36
在 Postman 中,我设置了完全相同的请求 header ,并向服务器发出了完全相同的 OPTIONS
请求。而且效果很好!我收到了空的 200 回复。
为了确定,我仔细检查了 Apache 访问日志。果然:
...
::1 - - [20/Sep/2017:15:33:24 -0400] "OPTIONS /the/path/to/api/users/13 HTTP/1.1" 200 -
::1 - - [20/Sep/2017:15:40:26 -0400] "OPTIONS /the/path/to/api/users/13 HTTP/1.1" 404 10
...
请求方法一模一样,请求URL一模一样,除了一个返回200,另一个返回404,没有明显的原因。
此外,我应该向 create
方法添加另一个 POST
请求,效果很好。
这可能是什么原因造成的?
<小时/>尝试的解决方案
1. 我看到了这个问题 ( React Native + fetch + API : DELETE request fails in App, works in Postman ),即使我运行的是 Apache,而不是 Nginx,我想我应该尝试在请求 URL 中添加尾部斜杠。 OPTIONS
请求现在返回 301 错误(永久移动)。
2. 我删除了结尾的斜杠并继续尝试修复。根据评论建议,我删除了自动路线生成并创建了自己的路线:
Route::get('/users', 'UserController@index');
Route::post('/users', 'UserController@create');
Route::put('/users/{user}', 'UserController@update');
Route::patch('/users/{user}', 'UserController@update');
Route::get('/users/{user}', 'UserController@show');
Postman请求仍然返回200 OK,React请求仍然返回404 Not Found。
3. Eureka ! 有点。根据另一条评论建议,我将 Chrome 中的请求导出为 cURL 并将其直接导入到 Postman 中 - 也许我在复制 header 时错过了一些内容。看来我做到了,因为现在 postman 请求也返回404!
在尝试禁用和/或启用导入的 header 后,我确定问题是 Origin
和 Access-Control 的组合 -Request-Method
header 。如果仅一个存在,则请求返回200,但如果两者都存在,我会收到404。
然而,这仍然给我留下了如何解决这个问题的问题。此时我想知道这个问题是否可能更多地变成一个 Laravel 问题 - IE,为什么对完全有效的资源路由的 OPTIONS 请求会返回 404。我认为是因为这些资源路由正在监听 PUT
或 PATCH
但不是 OPTIONS
。
最佳答案
既然您已经设置了 CORS,接下来您需要做的就是处理“预检”OPTIONS 请求。您可以使用中间件来做到这一点:
PreflightRequestMiddleware
:
if ($request->getMethod() === $request::METHOD_OPTIONS) {
return response()->json([],204);
}
return $next($request);
在新创建的中间件的handle()
方法中添加上述代码。将中间件添加到全局中间件堆栈中。
此外,不要忘记将 OPTIONS 方法添加到 CORS 设置中的 Access-Control-Allow-Methods
中。
有关更多选项,请查看this出来。
答案:
阅读this文章。当浏览器向您的应用程序发送 OPTIONS 请求时,应用程序无法处理它,因为您仅为给定端点定义了 GET/POST/DELETE/PUT/PATCH 路由。
因此,为了使该路由能够处理预检请求:
Route::get('/users', 'UserController@index');
它需要一个相应的 OPTIONS 路由:
Route::options('/users', 'UserController@options');
注意:您可以使用中间件在一个地方处理所有 OPTIONS 请求。但是,如果您将 OPTIONS 请求用于其他目的 - 请查看此答案中的第一个链接以获取更多选项。
关于apache - 完全相同的请求向 Postman 返回 200,但向 React App 返回 404,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46330826/