apache - 完全相同的请求向 Postman 返回 200,但向 React App 返回 404

标签 apache laravel reactjs

使用 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 后,我确定问题是 OriginAccess-Control 的组合 -Request-Method header 。如果仅一个存在,则请求返回200,但如果两者都存在,我会收到404。

然而,这仍然给我留下了如何解决这个问题的问题。此时我想知道这个问题是否可能更多地变成一个 Laravel 问题 - IE,为什么对完全有效的资源路由的 OPTIONS 请求会返回 404。我认为是因为这些资源路由正在监听 PUTPATCH 但不是 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/

相关文章:

java - hadoop mapreduce teragen FAIL_CONTAINER_CLEANUP

javascript - TypeError : Cannot read property 'state' of undefined. 但是状态可以成功console.logged(REACT)

php - 根据子类在父类中包含类

Laravel 模型 : query from multiple array

javascript - 如何在 React 的另一个 return 语句中返回多行 JSX?

javascript - react : Invariant Violation: Objects are not valid as a React child

apache - 在 apache 上的 modsecurity 中通过 ID 禁用规则

php - 带有 PHP 的 Docker Apache - 地址不可用:AH00056:连接到 [::]:80 上的监听器

apache - 使用多个 ProxyPass 配置 Apache

laravel - Docker中的PHP Artisan非常慢