web-dev-qa-db-ja.com

単純なcreate-react-appからJSON APIリクエストを行うときに405メソッドが許可されないエラー

次のリクエストでは、localhost:3000から単純なcreate-react-appで生成されたプロジェクトから実行すると、405メソッドは許可されません。私は本当にこのアプリをドメインの外で実行する必要があります(分離)。これはクロスオリジンの問題に非常によく似ていますが、X-CSRF-TOKENヘッダートークンと、ヘッダーを受け入れるように構成されたApacheがあります。

私が何を間違っているのかわからない...

Host: contenta.loc
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Access-Control-Request-Method: GET
Origin: http://localhost:3000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36
Access-Control-Request-Headers: authorization,x-csrf-token
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9

ただし、同じドメインのカスタムモジュール内から同じコードを実行すると、期待どおりに実行されます。

import React, { Component } from 'react';
import axios from 'axios';
import Querystring from 'query-string';
import SubRequests from 'd8-subrequests';

const URL = 'http://contenta.loc';

class App extends Component {

  state = {
      csrfToken: '',
      oauthToken: {}
  };

  constructor(props){
    super(props);

    this.initializeCsrfToken();
    this.initializeOauthToken();
  }

  initializeCsrfToken(){
    axios.get(URL + '/session/token')
    .then(response => {
      this.setState({csrfToken: response.data});
    })
    .catch((error) => {
      console.log('error ' + error);
    });
  }

  initializeOauthToken(){
    const data = {
      grant_type: 'password',
      client_id: '77e40506-4b2a-4317-b6c0-5ed5b27ce886',
      client_secret: 'test1123',
      username: 'test',
      password: 'test'
    };

    axios.post(URL + '/oauth/token', Querystring.stringify(data))
      .then(response => {
        this.setState({oauthToken: response.data.access_token});
      })
      .catch((error) => {
        console.log('error ' + error);
      });
  }


  fetchSubrequests() {
    const subrequests = new SubRequests(URL + '/subrequests?_format=json');
    const AuthStr = 'Bearer '.concat(this.state.oauthToken);

    subrequests.add({
      uri: '/api/categories'
    });

    subrequests.add({
      uri: '/api/tags'
    });
    subrequests.add({
      uri: '/api/menus'
    });

    axios.get(subrequests.getUrl(), {
      headers: {
        Authorization: AuthStr,
        'X-CSRF-Token': this.state.csrfToken,
      }
    }).then(dataresponse => {
      console.log(dataresponse);
    })

  }

  render = () => {
    return ( 
      <button >
        <div onClick ={
          () => {this.fetchSubrequests()}
        } > Fetch Subrequests</div> 
      </button>
    )
  }

}

export default App;


更新:

これが私のservices.yml cors.configは次のようになりました:(THIS IS WRONG ???)

   # Configure Cross-Site HTTP requests (CORS).
   # Read https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
   # for more information about the topic in general.
   # Note: By default the configuration is disabled.
  cors.config:
    enabled: true
    # Specify allowed headers, like 'x-allowed-header'.
    allowedHeaders: ['x-csrf-token,authorization,content-type,accept,Origin,x-requested-with']
    # Specify allowed request methods, specify ['*'] to allow all possible ones.
    allowedMethods: ['POST, GET, OPTIONS, DELETE, PUT']
    # Configure requests allowed from specific origins.
    allowedOrigins: ['*']
    # Sets the Access-Control-Expose-Headers header.
    exposedHeaders: true
    # Sets the Access-Control-Max-Age header.
    maxAge: false
    # Sets the Access-Control-Allow-Credentials header.
    supportsCredentials: false

これが機能するためには、cors.configが必要です。

cors.config:
    enabled: true
    # Specify allowed headers, like 'x-allowed-header'.
    # ['x-csrf-token,authorization,content-type,accept,Origin,x-requested-with']
    allowedHeaders: ['*']
      # - '*'
    # Specify allowed request methods, specify ['*'] to allow all possible ones.
    # ['POST, GET, OPTIONS, DELETE, PUT']
    allowedMethods: ['*']
    #  - '*'
    # Configure requests allowed from specific origins.
    allowedOrigins: ['*']
    # Sets the Access-Control-Expose-Headers header.
    exposedHeaders: true
    # Sets the Access-Control-Max-Age header.
    maxAge: false
    # Sets the Access-Control-Allow-Credentials header.
    supportsCredentials: false

これが私のApache.confは次のようになります。

<VirtualHost *:80>
  ServerName loc
  DocumentRoot /Users/justinwinter/Sites
  VirtualDocumentRoot /Users/justinwinter/Sites/%-2/docroot
  UseCanonicalName Off
  Header set Access-Control-Allow-Origin "http://localhost:3000"
  Header set Access-Control-Allow-Credentials true
  Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, PATCH, DELETE"
  Header always set Access-Control-Allow-Headers: "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization"

  <Directory "/Users/justinwinter/Sites/*/docroot">
    AllowOverride All
    Order allow,deny
    Allow from all
    Require all granted
  </Directory>

  AddType application/x-httpd-php .php
</VirtualHost>

個別のJS REACTアプリからは機能しません

次のスクリーンショットは、contenta.locドメイン(エンドポイントと同じサーバー)内から同じJSを実行した結果を示しています

Drupal Custom Module Implementation

カスタムモジュール内からの作業

次のスクリーンショットは、create-react-app nodejs localhostサーバー内からJSを実行したときのエラーを示しています。

405 (Method Not Allowed)

4

CORSサポートを有効にして、sites/default/services.ymlファイルを変更できます。

cors.config:
enabled: true
allowedHeaders:
  - '*'
allowedMethods:
  - '*'
allowedOrigins:
   # Note: you need to specify the Host + port where your app will run.
  - localhost:8000
exposedHeaders: false
maxAge: false
supportsCredentials: false
2
nuklive

たぶん['x-csrf-token', 'authorization', 'content-type', 'accept', 'Origin', 'x-requested-with']代わりに。

2
e0ipso

local.services.ymlフォルダーに配置できるsites/ファイルの作業例を次に示します。

# Local development services.
#
# To activate this feature, follow the instructions at the top of the
# 'example.settings.local.php' file, which sits next to this file.
parameters:
  http.response.debug_cacheability_headers: true
  cors.config:
      enabled: true
      # Specify allowed headers, like 'x-allowed-header'.
      allowedHeaders: ['*']
      # Specify allowed request methods, specify ['*'] to allow all possible ones.
      allowedMethods: ['*']
      # Configure requests allowed from specific origins.
      allowedOrigins: ['*']
      # Sets the Access-Control-Expose-Headers header.
      exposedHeaders: false
      # Sets the Access-Control-Max-Age header.
      maxAge: false
      # Sets the Access-Control-Allow-Credentials header.
      supportsCredentials: false
services:
  cache.backend.null:
    class: Drupal\Core\Cache\NullBackendFactory

たとえば sites/default/default.services.yml を確認してください。以下も確認してください: オプトインCORSサポート

ファイルは、設定ファイルからロードする必要があります。

/**
 * Enable local development services.
 */
$settings['container_yamls'][] = DRUPAL_ROOT . '/sites/local.services.yml';

Apacheを使用している場合は、 CORS on Apache も確認してください。

1
kenorb