【问题标题】:Lumen API CORS Ajax 405 Method Not Allowed不允许流明 API CORS Ajax 405 方法
【发布时间】:2023-03-10 17:51:01
【问题描述】:

我在 Laravel Lumen 上有一个 api,我们通过 Postman 和 Ruby Rest Client 进行测试,一切顺利,但我们创建了一个简单的身份验证登录来响应 Web 令牌,一切正常,但在我们的 React 应用程序上实际上我们有这个“405 405 方法不允许”。

我们用下面的代码创建一个类:

<?php namespace palanik\lumen\Middleware;

use Closure;
use Illuminate\Http\Response;

class LumenCors {

    protected $settings = array(
                'origin' => '*',    // Wide Open!
                'allowMethods' => 'GET,HEAD,PUT,POST,DELETE,PATCH,OPTIONS',
                );

    protected function setOrigin($req, $rsp) {
        $origin = $this->settings['origin'];
        if (is_callable($origin)) {
            // Call origin callback with request origin
            $origin = call_user_func($origin,
                                    $req->header("Origin")
                                    );
        }
        $rsp->header('Access-Control-Allow-Origin', $origin);
    }

    protected function setExposeHeaders($req, $rsp) {
        if (isset($this->settings['exposeHeaders'])) {
            $exposeHeaders = $this->settings['exposeHeaders'];
            if (is_array($exposeHeaders)) {
                $exposeHeaders = implode(", ", $exposeHeaders);
            }

            $rsp->header('Access-Control-Expose-Headers', $exposeHeaders);
        }
    }

    protected function setMaxAge($req, $rsp) {
        if (isset($this->settings['maxAge'])) {
            $rsp->header('Access-Control-Max-Age', $this->settings['maxAge']);
        }
    }

    protected function setAllowCredentials($req, $rsp) {
        if (isset($this->settings['allowCredentials']) && $this->settings['allowCredentials'] === True) {
            $rsp->header('Access-Control-Allow-Credentials', 'true');
        }
    }

    protected function setAllowMethods($req, $rsp) {
        if (isset($this->settings['allowMethods'])) {
            $allowMethods = $this->settings['allowMethods'];
            if (is_array($allowMethods)) {
                $allowMethods = implode(", ", $allowMethods);
            }

            $rsp->header('Access-Control-Allow-Methods', $allowMethods);
        }
    }

    protected function setAllowHeaders($req, $rsp) {
        if (isset($this->settings['allowHeaders'])) {
            $allowHeaders = $this->settings['allowHeaders'];
            if (is_array($allowHeaders)) {
                $allowHeaders = implode(", ", $allowHeaders);
            }
        }
        else {  // Otherwise, use request headers
            $allowHeaders = $req->header("Access-Control-Request-Headers");
        }

        if (isset($allowHeaders)) {
            $rsp->header('Access-Control-Allow-Headers', $allowHeaders);
        }
    }

    protected function setCorsHeaders($req, $rsp) {

        // http://www.html5rocks.com/static/images/cors_server_flowchart.png
        // Pre-flight
        if ($req->isMethod('OPTIONS')) {
            $this->setOrigin($req, $rsp);
            $this->setMaxAge($req, $rsp);
            $this->setAllowCredentials($req, $rsp);
            $this->setAllowMethods($req, $rsp);
            $this->setAllowHeaders($req, $rsp);
        }
        else {
            $this->setOrigin($req, $rsp);
            $this->setExposeHeaders($req, $rsp);
            $this->setAllowCredentials($req, $rsp);
        }
    }

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next) {

        if ($request->isMethod('OPTIONS')) {
            $response = new Response("", 200);
        }
        else {
            $response = $next($request);
        }

        $this->setCorsHeaders($request, $response);

        return $response;
    }

}

我们添加了 bootstrap/app.php

$app->routeMiddleware([
    'auth' => App\Http\Middleware\Authenticate::class,
    'cors' => palanik\lumen\Middleware\LumenCors::class,
]);

还有我们的路线:

$app->group(['middleware' => 'cors'], function($app)
{
    $app->post('/auth/login', function() {
        return response()->json([
            'message' => 'CORS OPTIONS Accepted.',
        ]);
    });
});

我们的其他客户端一切正常,但我在我们的 React js 应用程序上说的是因为浏览器发送一个 OPTIONS,请求不会传递给 POST。

我们的 Recat Axios 请求:

axios({
    method: 'post',
    url: 'URL',
    data: {
            email: 'Fred',
            password: 'Flintstone'
    }
    }).then(function (response) {
        console.log(response);
    })
    .catch(function (error) {
        console.log(error);
    });

错误反应日志: 问题是 OPTIONS 在浏览器的 POST 之前发送。 标头响应: HTTP/1.1 405 方法不允许 允许:发布 缓存控制:无缓存,私有 内容类型:文本/html;字符集=UTF-8 日期:2017 年 10 月 29 日星期日 01:30:34 GMT 服务器:Apache/2.4.18 (Ubuntu) 传输编码:分块 连接:保持活动

我们的 API 缺少什么?

问候。

【问题讨论】:

    标签: reactjs rest axios lumen


    【解决方案1】:

    在发送原始请求之前,React 会发送一个 Http 方法 Options 的请求,用于检查 API 服务器是否接受跨域请求?

    以下是我遵循的方法:

    添加方法option的通配符路由

    Route::options(
        '/{any:.*}', 
        [
            'middleware' => ['CorsMiddleware'], 
            function (){ 
                return response(['status' => 'success']); 
            }
        ]
    );
    

    CorsMiddleware 是用于处理请求的中间件。

    <?php 
    
    namespace App\Http\Middleware;
    
    use Closure;
    use Illuminate\Http\Response;
    
    class CorsMiddleware
    {
        protected $settings = array(
            'origin' => '*',    // Wide Open!
            'allowMethods' => 'GET,HEAD,PUT,POST,DELETE,PATCH,OPTIONS',
        );
    
        protected function setOrigin($req, $rsp) {
            $origin = $this->settings['origin'];
            if (is_callable($origin)) {
                // Call origin callback with request origin
                $origin = call_user_func($origin,
                            $req->header("Origin")
                        );
            }
            $rsp->header('Access-Control-Allow-Origin', $origin);
        }
    
        protected function setExposeHeaders($req, $rsp) {
            if (isset($this->settings['exposeHeaders'])) {
                $exposeHeaders = $this->settings['exposeHeaders'];
                if (is_array($exposeHeaders)) {
                    $exposeHeaders = implode(", ", $exposeHeaders);
                }
    
                $rsp->header('Access-Control-Expose-Headers', $exposeHeaders);
            }
        }
    
        protected function setMaxAge($req, $rsp) {
            if (isset($this->settings['maxAge'])) {
                $rsp->header('Access-Control-Max-Age', $this->settings['maxAge']);
            }
        }
    
        protected function setAllowCredentials($req, $rsp) {
            if (isset($this->settings['allowCredentials']) && $this->settings['allowCredentials'] === True) {
                $rsp->header('Access-Control-Allow-Credentials', 'true');
            }
        }
    
        protected function setAllowMethods($req, $rsp) {
            if (isset($this->settings['allowMethods'])) {
                $allowMethods = $this->settings['allowMethods'];
                if (is_array($allowMethods)) {
                    $allowMethods = implode(", ", $allowMethods);
                }
    
                $rsp->header('Access-Control-Allow-Methods', $allowMethods);
            }
        }
    
        protected function setAllowHeaders($req, $rsp) {
            if (isset($this->settings['allowHeaders'])) {
                $allowHeaders = $this->settings['allowHeaders'];
                if (is_array($allowHeaders)) {
                    $allowHeaders = implode(", ", $allowHeaders);
                }
            }
            else {  // Otherwise, use request headers
                $allowHeaders = $req->header("Access-Control-Request-Headers");
            }
            if (isset($allowHeaders)) {
                $rsp->header('Access-Control-Allow-Headers', $allowHeaders);
            }
        }
    
        protected function setCorsHeaders($req, $rsp) {
            // http://www.html5rocks.com/static/images/cors_server_flowchart.png
            // Pre-flight
            if ($req->isMethod('OPTIONS')) {
                $this->setOrigin($req, $rsp);
                $this->setMaxAge($req, $rsp);
                $this->setAllowCredentials($req, $rsp);
                $this->setAllowMethods($req, $rsp);
                $this->setAllowHeaders($req, $rsp);
            }
            else {
                $this->setOrigin($req, $rsp);
                $this->setExposeHeaders($req, $rsp);
                $this->setAllowCredentials($req, $rsp);
            }
        }
        /**
         * Handle an incoming request.
         *
         * @param  \Illuminate\Http\Request  $request
         * @param  \Closure  $next
         * @return mixed
         */
        public function handle($request, Closure $next) {
            if ($request->isMethod('OPTIONS')) {
                $response = new Response("", 200);
            }
            else {
                $response = $next($request);
            }
            $this->setCorsHeaders($request, $response);
            return $response;
        }
    }
    

    加载bootstrap/app.php的中间件$app-&gt;routeMiddleware部分

    保持组中的所有应用程序 URL 检查CorsMiddleware

    Route::group(['middleware' => 'CorsMiddleware'], function($router){
        $app->post('/auth/login', function() {
            return response()->json([
                'message' => 'CORS OPTIONS Accepted.',
            ]);
        });
    }
    

    【讨论】:

    • 此答案已在 Lumen 5.5 中应用 OK
    • 这确实有效!!!非常感谢,我们尝试了很多其他选项和库,但这很简单并且有效。
    • 这个答案很有用,非常感谢。
    • 对我有用,非常感谢
    【解决方案2】:

    最后我找到了一个干净的方法。只需将以下几行添加到.htaccess(如果您不知道,.htaccess 已位于public/.htaccess):

    <IfModule mod_headers.c>
        Header add Access-Control-Allow-Origin "*"
        Header set Access-Control-Allow-Headers "*"
        Header set Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"
    </IfModule>
    

    然后,像这样在你的 Laravel/Lumen 应用程序中定义一个路由:

    Route::options('/{any:.*}', function() { return response(['status' => 'success']); });};
    

    当然你需要mod-rewritemod-headers。您可以使用以下命令(Ubuntu)启用它们(如果尚未启用):

    a2enmod rewrite
    a2enmod headers
    systemctl reload apache2
    

    【讨论】:

      【解决方案3】:

      您可以添加应该返回 200 代码的简单 OPTIONS 处理程序 这是一个有用的集成示例:

      https://gist.github.com/danharper/06d2386f0b826b669552

      【讨论】:

      • 我试过了,但现在我得到“301 Moved Permanently”,但其他工作正常。
      猜你喜欢
      • 2014-01-09
      • 2016-08-05
      • 2013-03-13
      • 2017-05-31
      • 2018-06-16
      • 1970-01-01
      • 2013-03-21
      • 2016-01-23
      • 1970-01-01
      相关资源
      最近更新 更多