web-dev-qa-db-ja.com

create-react-appおよびwebpackを使用したCORS APIリクエストの作成-エクスプレスなし

ブラウザでCORSを無効にせずにAPI呼び出しを行おうとしています。アプリはreact-create-appを使用して作成されました。開発にはwebpackとwebpackDevServerを使用しています。ここで見つけたすべての答えは、次のコードをwebpack.configファイル。

devServer: {
      headers: {
        "Access-Control-Allow-Origin": "*",
        "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
        "Access-Control-Allow-Headers": "X-Requested-With, content-type, Authorization"
      }
  }

ただし、さまざまな場所で試してみましたが、機能しません。

エラーが発生し続けます:

リソースの読み込みに失敗しました:サーバーは500()のステータスで応答しました

そして

ロードに失敗しました...プリフライト要求への応答がアクセス制御チェックに合格しません:要求されたリソースに「Access-Control-Allow-Origin」ヘッダーがありません。したがって、オリジン ' http:// localhost:30 'はアクセスを許可されません。応答のHTTPステータスコードは500でした。

また、自分の呼び出しをaxios呼び出しからフェッチ呼び出しに変更しようとしました

return fetch(process.env.REACT_APP_API_URL + "/prod/user", {
    mode: 'no-cors',
    credentials: 'include',
    method: "GET",
    headers: {
        "x-api-key": process.env.REACT_APP_API_KEY
    }
})
.then(response => {
   return response.json()
})
.then(resp => dispatch(receiveUsers(resp.data)))
.catch(error => {console.log(error)})

これで近づきましたが、コンソールが戻ってきました

Response {type: "opaque", url: "", redirected: false, status: 0, ok: false, …}

このCORSの問題を回避するにはどうすればよいですか?よろしくお願いします!

応答/要求ヘッダー

4
Tim

プリフライトOPTIONSリクエストに対する500応答が表示されるという事実は、おそらくOPTIONSリクエストメソッドがWebサーバーで許可されていないだけだと思います。

多くのWebサーバーでは、デフォルトでHEAD、GET、POSTのみが許可されているため、これを最初に確認します。

それでも問題が解決しない場合は、上記のwebpack.configコードはすべてのリクエストに対して実行されます(つまり、OPTIONSおよびGET/POSTに対して)。

それでも問題が解決しない場合は、リクエストヘッダーとレスポンスヘッダーの完全なセットをOPTIONSリクエストとGETリクエストの両方に投稿し、そこからどこに行くのか見てみましょう。

1
roryhewitt

コメントはまだ追加できませんので、回答させていただきます。

別のノードアプリまたは別のホストによって提供されるAPIにアクセスしようとしている場合。その要求を実サーバーにプロキシするようにwebpack-dev-serverを構成できます。

詳細については、 Create React App Doc:Proxying API Requests in Development を確認してください。

3
loveky

特に外部APIまたは複数のAPIを使用する場合は、プロキシを使用するのが最善の方法です。 _proxy-middleware_をインストールして_src/setupProxy.js_ファイルを作成し、ファイル内に同様のコードを追加できます。

_const proxy = require('proxy-middleware');

module.exports = app => {
  // setup proxies
  // 1st api
  app.use("/etherscan", proxy("http://api.etherscan.io/api"));
  // 2nd api
  app.use("/cryptocompare", proxy("https://min-api.cryptocompare.com/data"));

  // Note: setupProxy is an express server so you can also override anything in the req or res before proxy them for example 
  app.use("/cryptocompare", (req,res,next) => {
     req.headers = { 
        ...req.headers,
        "my-header":"my header value"
     }
     return proxy("https://min-api.cryptocompare.com/data")(req,res,next);
  });

  app.use("/cryptocompare", proxy("https://min-api.cryptocompare.com/data"));


  // also it's better to use .env variables
  // const {REACT_APP_API_ETHERSCAN_PROXY, REACT_APP_API_ETHERSCAN_BASE_URL} = process.env;
  // app.use(REACT_APP_API_ETHERSCAN_PROXY, REACT_APP_API_ETHERSCAN_BASE_URL);      
};
_

また、APIの場合、たとえば.env変数からベースURLを取得できるとさらに優れています。

_const {REACT_APP_API_ETHERSCAN_PROXY, REACT_APP_API_ETHERSCAN_BASE_URL} = process.env;
const baseURL = REACT_APP_API_ETHERSCAN_PROXY || REACT_APP_API_ETHERSCAN_BASE_URL;
_

追加のアドバイス:すべてのAPI呼び出しに対してprocess.env.REACT_APP_API_URLとヘッダーを渡し続ける代わりに、デフォルトのプロパティを使用してAPIインスタンスを作成できる axios を確認できます:

_const {
  REACT_APP_API_ETHERSCAN_PROXY, 
  REACT_APP_API_ETHERSCAN_BASE_URL,
  REACT_APP_API_TIMEOUT,
  REACT_APP_API_ETHERSCAN_KEY
} = process.env;

export const etherscanAPI = axios.create({
  "baseURL": REACT_APP_API_ETHERSCAN_PROXY || REACT_APP_API_ETHERSCAN_BASE_URL,
  "timeout": parseInt(REACT_APP_API_TIMEOUT),
  "headers": {
    "X-Requested-With": "XMLHttpRequest"
  },
  "params": {
    "apiKey": REACT_APP_API_ETHERSCAN_KEY
  }
});
_

次にetherscanAPI.get("/whatever")

1