无法访问 api post 方法,总是请求 OPTIONS

Posted

技术标签:

【中文标题】无法访问 api post 方法,总是请求 OPTIONS【英文标题】:Can't access api post method, request always OPTIONS 【发布时间】:2019-12-06 04:19:42 【问题描述】:

我正在尝试使用 nuxtjs 作为前端和 slim php 作为后端 api 创建登录表单,当我尝试访问 API 时,我看到我发送的请求方法是 OPTIONS 而不是 POST,并在 chrome 开发控制台错误显示请求被阻止 (CORS)。 我知道我必须设置 Access-Control-Allow-Methods 添加 OPTIONS 到其中,但仍然失败,在哪里设置 nuxt js(nuxt.config) 或 slim php?

我尝试从邮递员访问 api,它工作得很好,我可以看到 Access-Control-Allow-Methods 标头中有 OPTIONS,但是当我在 vue 中尝试时仍然失败应用程序

commons.app.js:434 OPTIONS http://localhost:8080/login 401 (Unauthorized)

Access to XMLHttpRequest at 'http://localhost:8080/login' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

来自 slim php (API) 的代码

routes.php

// login routes
$app->post('/login', function (Request $request, Response $response, array $args) 

        $input = $request->getParsedBody();
        $sql = "SELECT * FROM groups
                LEFT JOIN users_groups ON groups.groups_id = users_groups.users_groups_id
                LEFT JOIN users ON users_groups.users_groups_id = users.id
                WHERE users.email = :email";
        $sth = $this->db->prepare($sql);
        $sth->bindParam("email", $input['email']);
        $sth->execute();
        $user = $sth->fetchObject();

        // verify email address.
        if (!$user) 
            $container->get('logger')->info("Error trying to login with email : ".$input['email']);
            return $this->response->withJson(['error' => true, 'message' => 'These credentials do not match our records.']);
        

        // verify password.
        if (!password_verify($input['password'], $user->password)) 
            $container->get('logger')->info("Error trying to login with password : ".$input['password']);
            return $this->response->withJson(['error' => true, 'message' => 'These credentials do not match our records.']);
        

        // cek apakah sudah login sebelumnya hari ini untuk user ini
        $absensiSql = "SELECT * FROM users_presensi WHERE user_id = :userID";
        $sth = $this->db->prepare($absensiSql);
        $sth->bindParam("userID", $user->id);
        $sth->execute();
        $absensi = $sth->fetchObject();

        // jika belum absen, masukan user ke absensi
        if(!$absensi)
            $status = 1;
            $absensiSql = "INSERT INTO users_presensi(user_id, statuss) VALUES (:userID, :statuss)";
            $sth = $this->db->prepare($absensiSql);
            $sth->bindParam("userID", $user->id);
            $sth->bindParam("statuss", $status);
            $sth->execute();
            // $absensi = $sth->fetchObject();s
        

        $settings = $this->get('settings'); // get settings array.

        $token = JWT::encode(['id' => $user->id, 'email' => $user->email, 'level' => $user->groups_level], $settings['jwt']['secret'], "HS256");

// i already set the header here
        return $this->response
        ->withHeader('Access-Control-Allow-Origin', '*')
        ->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization')
        ->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
        ->withHeader('Set-Cookie', "token=$token; httpOnly")
        ->withJson(['token' => $token]);

    )->setName('login');

我的 nuxtjs 身份验证配置 nuxt.config.js

/*
  ** Nuxt.js modules
  */
  modules: [
    '@nuxtjs/vuetify',
    // Doc: https://axios.nuxtjs.org/usage
    '@nuxtjs/axios',
    '@nuxtjs/pwa',
    '@nuxtjs/eslint-module',
    '@nuxtjs/auth'
  ],
  /*
  ** Axios module configuration
  ** See https://axios.nuxtjs.org/options
  */
  axios: 
  ,

  /**
   * set auth middleware
   */
  router: 
    middleware: ['auth']
  ,
  auth: 
    strategies: 
      local: 
        endpoints: 
          login:  url: 'http://localhost:8080/login', method: 'post', propertyName: 'token' 
        
        // tokenRequired: true,
        // tokenType: 'bearer'
      
    
  

从 login.vue 方法登录

   loginPost: function () 
      this.$auth.loginWith('local', 
        data: 
          username: this.loginData.username,
          password: this.loginData.password
        
      )
    

在邮递员中,结果是令牌本身,我认为不应该发生 cors 错误,但谁知道。

【问题讨论】:

【参考方案1】:

我不了解其他浏览器,但我知道 Chrome 不支持在您的 Access-Control-Allow-Origin 标头中使用 localhost。你应该做的是在你的开发环境中只告诉它接受所有来源->withHeader('Access-Control-Allow-Origin', '*')

OPTIONS 请求是为准备浏览器发出真正的请求以确定 CORS 规则是什么而发出的。

【讨论】:

我按照您的建议编辑我的代码(routes.php),但即使在响应标头(在 chrome dev 中)显示 Access-Control-Allow-Headers: content-type Access-Control-Allow-Methods: GET, PUT, POST, DELETE, HEAD, OPTIONS Access-Control-Allow-Origin: * 我也有尝试安装 CORS(chrome 扩展)我的问题仍然存在。 我想到了几件事:我知道一些后端框架希望所有 POST 请求的内容类型为 application/x-www-form-urlencoded,而 axios 将其设置为 application/javascript。我不知道loginWith 函数是如何工作的,但我在项目中使用 Nuxt 中间件时遇到了麻烦。我不记得那些麻烦在哪里,但我直接调用了$axios.post$axios.get函数,这对我有用。 你可以看看这个 SO 答案。也许它会帮助你。 ***.com/questions/12630231/… 哎呀,我忘了在我的苗条应用程序中,我正在使用 corsmiddleware(使用 tuupola),我忘了设置它。 我很高兴你能找出问题所在。

以上是关于无法访问 api post 方法,总是请求 OPTIONS的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Slim 中访问 POST 请求的 JSON 请求正文?

.NET CORE API 使用Postman中Post请求获取不到传参问题

springsecurity解决post请求403问题

php 中发送get请求,后台无法获取

Ionic 2 / Angular 问题与 http post 到 laravel api

无法从 Spotify API 获取访问令牌