Serverless関数によるCORSを克服する方法



問題
最近私は仕事をしていましたFrontend Mentor challenge , IPアドレスまたはURLを入力することができますし、取得し、それについての情報を表示するアプリ.

事態は順調だった.私はレイアウトの並べ替えを得た、私はカスタムリーフレットとMapboxを使用してカスタムマップを設定します.
しかし、APIからデータを取得する時間だったとき、私は問題に出くわしました.
フロントエンドメンターはIP Geolocation API by IPify IPアドレスまたはドメインから情報を取得するには.
あなたがiPifyと貼り付けで無料のアカウントにサインアップする場合https://geo.ipify.org/api/v1?apiKey=YOUR_API_KEY あなたのURLバーに、それはあなたのIPアドレス、場所、およびあなたのISPプロバイダに関する情報をJSONに送り返すでしょう.
しかし、クライアント側のコードからこのAPIにHTTPリクエストを作成しようとすると、Corsに関するメッセージが得られます.


Corsとは
CORS (Cross Origin Resource Sharing) HTTPヘッダーを使用して、要求を行うウェブサイトのサーバーと異なるサーバーからリソースへのアクセスを許可するブラウザの許可を与える仕組みです.
それは非常に良い理由のために存在する:セキュリティ.いくつかのランダムなウェブサイトをあなたのサーバーをpingし、それからの敏感なデータを取得できるようにしたくない.これを防ぐために、ブラウザはクライアント側スクリプトから開始されたクロスルートのHTTPリクエストをデフォルトで制限します.
あなたはどのようなURLは、正しいCorsのヘッダーは、各要求で送信されることを確認することによって、サーバーからデータにアクセスできるように指定する必要があります.しかし、それはちょうどセキュリティ層としてCorsの全体のポイントを破るので、他の誰かのサーバ上のCORS設定を変更することはできません.

コルクスプロキシ
ほとんどのリソースが推奨するソリューションは、プロキシを使用して、別のサーバーからの要求を受信し、アクセスしようとしているサーバーに渡すと、そのサーバーの応答を返します.このようにしてリクエスト応答プロセス全体がサーバ側で発生し、CORSには影響しません.
あなたが使用できるCorsプロキシの数がありますcrossorigin.me or CORS Anywhere .
しかし、私は第三者代理に頼りたくありませんでした.結局のところ、彼らはあなたがそれらに渡すすべてのデータを見ることができるといつでも動作を停止することができます.私も実行して自分のノードのアプリを管理するだけでプロキシとして動作するようにしなかった.
若干の研究をしている間、私はジムニールセンによってブログ柱に遭遇しましたsetting up a CORS proxy with Netlify それはあなた自身のプロキシサーバを走らなければならないか、若干のランダムなものに頼ることなくNetlifyリダイレクトを使用しているCors問題を解決すると約束しました.

リダイレクトする
リダイレクトルールを外部サービスへのプロキシに使用すると、NetLifyが積極的にサポートするものです.たとえば、任意の要求をするように設定することができます/api/searchhttps://api.example.com/search . The Netlify docs 方法を説明しなさい.
リダイレクトルールを設定するには_redirects ファイル
/api/*  https://api.example.com/:splat  200
またはあなたの中に含めることができますnetlify.toml NetLify上のアプリケーション全体の設定を設定するファイル.
[[redirects]]
  from = "/api/*"
  to = "https://api.example.com/:splat"
  status = 200
  force = true
これを展開する前にローカルでテストしたい場合はNetlify Dev あなたのマシン上のローカルローカルを実行できます.
この情報で武装して、私のリダイレクトルールをnetlify.toml ファイルをnetlify dev コマンドとそれは働いた!
改善するためには、私はNetlifyにアプリを展開している.そして新しい問題に乗り出した.
すべてがローカルに働いたが、アプリが展開された後、私は502 Bad Gateway 応答は、プロキシサーバがプロキシサーバから無効な応答を受信したことを意味します.

Netlifyは本当に素晴らしいSupport Forums そして、そこの良い人々は私に潜在的解決を示しました--私のリダイレクトの特定のヘッダーを設定して、私のローカル環境とNetLifyの上で構築環境の違いをチェックしてください.しかし、これのどれも違いを生じませんでした.
Netlifyエンジニアは、問題がAPIが30秒以内に要求に応じていなかったということを確認することができました.プロキシの書き換えについては、netlifyは30秒で接続を終了し、その後リクエストが完了していないため502を返す.彼らは私のコードをServerlessな関数に動かして、それが問題を解決するかどうか見ることを提案しました.

解決- Serverless関数
Serverless関数を使用すると、APIエンドポイントのように動作するサーバーサイドコードを記述できます.イベントに応答して自動的に実行したり、バックグラウンドで複雑なジョブを処理することができます.
Netlify Functions セットアップを作成し、簡単にServerless関数を実行します.
あなたはfunctions あなたのプロジェクトのルートのディレクトリ、そして、その中に、あなたの機能の名前を持つJavaScriptファイル.
base-directory/
|- package.json
|- node_modules
|- functions/
   hello.js
関数のファイルで、ステータスコードと本体を返すAsyncHandler関数をエクスポートします.これらの関数は、APIからデータを取り出したり、自動メールを送信したり、ユーザ入力を検証したりするなどのタスクを実行できます.
exports.handler = async (event, context) => {
  return { statusCode: 200, body: JSON.stringify({ message: "Hello World" }) };
};
デフォルトでは、Serverless関数を呼び出します.netlify/functions/your-serverless-function . しかし、あなたもあなたのnetlify.toml これをより簡潔にするために.
[build]
  functions = "functions"

[[redirects]]
  from = "/api/*"
  to = "/.netlify/functions/:splat"
  status = 200
さて、リクエスト/api/hello.netlify/functions/hello .

リクエストのカスタマイズ
APIリクエストをServerless関数に移動し、netlify devを実行し、すぐにIP情報を取得できました.
しかし、この特定のプロジェクトのために、私はAPIに送ったリクエストを変えることができる必要がありました.
要求https://geo.ipify.org/api/v1?apiKey=YOUR_API_KEY リクエストを送信したIPアドレスについての情報を返します.
一方で、要求https://geo.ipify.org/api/v1?apiKey=YOUR_API_KEY&ipAddress=SOME_IP_ADDRESS は指定したIPアドレスに関する情報を返す.
そして最後にhttps://geo.ipify.org/api/v1?apiKey=YOUR_API_KEY&domain=SOME_DOMAIN はそのドメインに関する情報を返す.
しかし、どのように私はこのデータをServerless関数に渡すつもりでしたか?
さて、ありがたいことに、ベンホンは役に立つチュートリアルを持っていますcustomizing the request with serverless functions .
基本的には、フェッチを使ってServerless関数にポストリクエストを行い、検索入力の値をリクエストの本文として渡します.
// App.js
const res = await fetch(`/api/getIpInfo`, {
  method: "POST",
  body: JSON.stringify({
    searchTerm: ipAddress,
  }),
});
const ipInfo = await res.json();
次に、サーバなし関数では、使用した体から検索語を抽出しましたvalidator.js IPアドレスまたはドメインであるかどうかをチェックし、APIエンドポイントに追加しました.
// getIpInfo.js
const fetch = require("node-fetch");
const validator = require("validator");

exports.handler = async (event, context) => {
  const eventBody = JSON.parse(event.body);

  // Check for IP Address or domain
  let extension = "";
  if (eventBody.searchTerm) {
    const { searchTerm } = eventBody;
    if (validator.isIP(searchTerm)) {
      extension = `&ipAddress=${searchTerm}`;
    } else if (validator.isURL(searchTerm)) {
      const domain = new URL(searchTerm);
      extension = `&domain=${domain.hostname}`;
    }
  }

  try {
    const res = await fetch(`${API_ENDPOINT}${extension}`);
    const data = await res.json();
    return { statusCode: 200, body: JSON.stringify({ data }) };
  } catch (error) {
    console.log(error);
    return {
      statusCode: 500,
      body: JSON.stringify({ error: "Failed fetching data" }),
    };
  }
};
成功!Serverless関数のおかげで、私のアプリは現在、任意のCorsの問題に実行せずに、ブラウザからIPジオロケーションAPIへの要求を行うことができます.

自分で試してみて
ブラウザからHTTPリクエストを作成するときにCorsの問題に実行している場合は、リダイレクトを介してプロキシを試してみてください、そして、それはあなたのために動作しない場合は、サーバーレス機能について学ぶためのより良い時間をされたことがない.
ベンホーUp and Running with Serverless Functions 始めるにはいい場所です.
私のプロジェクト用のコードはGitHub . また、試してみることができますdeployed app .

更なる資源
  • アニアKubさんw
  • ベンホンUp and Running with Serverless Functions - Jamstack探検家
  • Cross-Origin Resource Sharing (CORS) - MDNウェブドキュメント
  • ジム・ニールセンSetup a CORS Proxy With Netlify - ジム・ニールセン.コム
  • フィルホークスワースExploring Netlify Redirects - Jamstack探検家