Lumen API CORS Ajax 405方法不允许

时间:2017-10-29 01:46:04

标签: reactjs rest axios lumen

我在Laravel Lumen上有一个api,我们通过Postman和Ruby Rest Client进行测试,一切都很顺利,但是我们创建了一个简单的Auth Login来响应Web令牌,一切正常,但在我们的React App上实际上我们有这个“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);
    });

错误con React log: 问题是OPTIONS在POST之前发送给浏览器。 标题回复:     HTTP / 1.1 405方法不允许     允许:POST     缓存控制:无缓存,私有     内容类型:text / html;字符集= UTF-8     日期:太阳,2017年10月29日01:30:34 GMT     服务器:Apache / 2.4.18(Ubuntu)     transfer-encoding:chunked     连接:保持活力

我们在API上缺少什么?

问候。

3 个答案:

答案 0 :(得分:2)

在发送原始请求之前,React发送Http方法选项请求,检查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;
    }
}

加载$app->routeMiddleware

的中间件bootstrap/app.php部分

将所有应用程序网址保留在组中,检查CorsMiddleware

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

答案 1 :(得分:1)

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

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

答案 2 :(得分:0)

最后,我找到了一种干净的方法。只需将以下行添加到.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