OPTIONS请求获得“ 401未经授权”响应

时间:2020-01-10 12:29:57

标签: javascript jquery api cors symfony4

我使用Symfony 4编写了一个使用自定义令牌验证的API。我在Postman上测试了API,并且一切正常,现在我想使用jQuery使用API​​并提取所有数据,但是在浏览器中,我遇到了以下CORS问题:

从原点“ http://localhost:8000/api/reports”到“ http://localhost:8080”的XMLHttpRequest的访问已被CORS策略阻止:对预检请求的响应未通过访问控制检查:它没有HTTP正常状态。

这是我的服务器端API:

我已经实现了CORSEventSubscriber以允许CORS如下所示:

class CORSSubscriber implements EventSubscriberInterface
{

/**
 * @var TokenStorageInterface
 */
private $tokenStorage;

public function __construct(TokenStorageInterface $tokenStorage)
{
    $this->tokenStorage = $tokenStorage;
}
public function onKernelResponse(FilterResponseEvent $event)
{
    $responseHeaders = $event->getResponse()->headers;
    $responseHeaders->set('Access-Control-Allow-Origin', '*');
    $responseHeaders->set('Access-Control-Allow-Headers', 'x-auth-token, content-type');
    $responseHeaders->set('Access-Control-Allow-Methods', 'POST, GET');
}

/**
 * @inheritDoc
 */
public static function getSubscribedEvents()
{
    return [
        KernelEvents::RESPONSE => 'onKernelResponse',
    ];
}

这是我在控制器中调用的操作:

/**
 * @Route("/api/reports",name="reports",methods={"GET","OPTIONS"})
 * @param Request $request
 * @return Response
 * @throws  Exception
 */
function getReports(Request $request){

return new JsonResponse('test', Response::HTTP_UNAUTHORIZED);

}

我试图像这样食用API

    <script>
    $(document).ready(function(){

        authenticate().then(function (data) {
           // the promise resolve the token and data.token output the correct value
           $.ajax({
               url:'http://localhost:8000/api/reports',
               type: 'GET',
                headers: {'X-Auth-Token' : data.token },
               success: function (data) {
                   //append data to your app
                   console.log(data);
               }
           })
        })
    });
    function authenticate() {
        let data={
            "username": "test",
            "password": "test"
        };
        return new Promise(function(resolve, reject) {
            $.ajax({
                url:'http://localhost:8000/api/auth/check',
                type:'POST',
                data:JSON.stringify(data),
                dataType:'Json',
                success: function (data) {
                    console.log(data);
                resolve(data);
                },
                error:function () {
                }
            })
        });
    }


</script>

我添加此代码是为了仔细调试问题,我发现只有在像POST这样的令牌方法无法执行时,该函数才对OPTIONS执行

public function onKernelRequest(GetResponseEvent $event)
{
    $this->logger->info($event->getRequest()->getRealMethod());
}

2 个答案:

答案 0 :(得分:3)

您正在发出跨域请求,并添加了非标准标头。这意味着它是Preflighted Request

浏览器正在发送一个OPTIONS请求,以请求允许使用自定义标头进行该请求。

您无法控制预检请求的格式。您绝对不能向其添加凭据。 (添加凭据是将简单的请求转换为预检请求的另一件事)。

您需要通过CORS标头获得许可,以响应OPTIONS请求。由于该请求没有任何关联的凭据,因此您的服务器不需要凭据

更改服务器以在请求类型为OPTIONS时删除对凭据的要求。


我不知道如何使用您所使用的服务器端框架,但是从您提供的代码中推断,我怀疑您应该为GET和OPTIONS提供单独的路由

OPTIONS请求应与CORS仅涉及 (而不是获取任何需要授权的数据)。

GET请求应要求授权并返回数据。

答案 1 :(得分:1)

几天后,我通过添加到CorsSubscriber

public function onKernelResponse(FilterResponseEvent $event)
{

    $responseHeaders = $event->getResponse()->headers;
    $responseHeaders->set('Access-Control-Allow-Origin', 'http://localhost:8080');
    $responseHeaders->set('Access-Control-Allow-Credentials', 'true');
    $responseHeaders->set('Access-Control-Allow-Headers', ' content-type ,x-auth-token');
    $responseHeaders->set('Access-Control-Allow-Methods', 'POST, GET');
    if($event->getRequest()->getRealMethod()=='OPTIONS'){
        $responseHeaders->set('Access-Control-Max-Age', '1728000');
        $event->getResponse()->setStatusCode(200);
    }

}

处理响应后,我将200作为状态码发送给我,这样我就不会遇到任何CORS问题