terisuke
@terisuke (寺田 康佑)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

Firebase HostingデプロイメントでのGCPにホストされたVoiceVox APIとのCORS問題

解決したいこと

Firebase HostingデプロイメントでのGCPにホストされたVoiceVox APIとのCORS問題を解決したいです。

発生している問題・エラー

Access to fetch at 'https://voicevox-proto-mggisi6odq-dt.a.run.app/audio_query?speaker=2&text=%20%E3%81%9D%E3%81%86%E3%81%A0%E3%81%AD%EF%BC%81' from origin 'https://aipartner-426616.web.app' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

該当するソースコード

// functions/src/index.ts
import * as functions from 'firebase-functions';
import express from 'express';
import cors from 'cors';

const app = express();
app.use(cors({ origin: true }));

app.get('/hello', (req, res) => {
  res.send('Hello from Firebase!');
});

exports.api = functions.region('asia-east1').https.onRequest(app);

例)

// firebase.json
{
  "functions": {
    "source": ".firebase/aipartner-426616/functions",
    "runtime": "nodejs14"
  },
  "hosting": {
    "public": "out",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "**",
        "function": "api"
      }
    ]
  }
}

// フロントエンドのリクエスト例
const VOICE_VOX_API_URL = process.env.NEXT_PUBLIC_VOICE_VOX_API_URL || 'http://localhost:50021';

export const fetchAudioVoiceVox = async (
  talk: Talk,
  speaker: string
): Promise<ArrayBuffer> => {
  const ttsQueryResponse = await fetch(VOICE_VOX_API_URL + '/audio_query?speaker=' + speaker + '&text=' + encodeURIComponent(talk.message), {
    method: 'POST',
  });
  if (!ttsQueryResponse.ok) {
    throw new Error('Failed to fetch TTS query.');
  }
  const ttsQueryJson = await ttsQueryResponse.json();

  ttsQueryJson['speedScale'] = 1.16;
  ttsQueryJson['pitchScale'] = -0.02;
  ttsQueryJson['intonationScale'] = 1.26;
  const synthesisResponse = await fetch(VOICE_VOX_API_URL + '/synthesis?speaker=' + speaker, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', 'Transfer-Encoding': 'chunked' },
    body: JSON.stringify(ttsQueryJson)
  });
  if (!synthesisResponse.ok) {
    throw new Error('Failed to fetch TTS synthesis result.');
  }
  const blob = await synthesisResponse.blob();
  const buffer = await blob.arrayBuffer();
  return buffer;
}

自分で試したこと

1.CORSミドルウェアを使用したFirebase Functionsの設定:
cors ミドルウェアを含むExpressアプリを持つFirebase Functionを作成しました。

2.Firebaseの設定:
functionsとhostingを設定するために firebase.json を更新しました。

3.FunctionレスポンスでのCORSヘッダー設定:
Firebase FunctionのレスポンスでCORSヘッダーを明示的に設定しました。

4.デプロイ:
firebase deploy --only functions,hosting を使用してfunctionsとhostingをデプロイしました。

上記の手順を踏んだにもかかわらず、デプロイされたフロントエンドからAPIにアクセスするとCORSエラーが発生し続けています。同じAPIリクエストはローカル開発時には問題なく動作します。

このCORS問題を解決するためのガイダンスや提案をいただけると幸いです。よろしくお願いします。

0

1Answer

デプロイされたフロントエンドからAPIにアクセスするとCORSエラーが発生し続けています。同じAPIリクエストはローカル開発時には問題なく動作します。

Fiddler などのツールを使って要求・応答をキャプチャし、問題があるときと無いときを比較するとヒントが見つかるかもしれません。

【追記】

Fiddler で見ると何が分かるかは以下の記事が参考になると思います。記事の真ん中あたりに「Fiddler で見た時の要求・応答は以下のようになります。・・・」と書いた下の画像を見てください。

CORS 非対応の場合のエラーメッセージ
http://surferonwww.info/BlogEngine/post/2024/04/02/error-messages-when-cors-is-not-working-at-server-side.aspx

【追記2】

同じAPIリクエストはローカル開発時には問題なく動作します。

とのことでしたが、実はバックエンド voicevox-proto-mggisi6odq-dt.a.run.app が CORS 対応してないのかもしれないと思って、自分の開発環境から(当然クロスドメインになります)、以下のスクリプトで要求をかけてみました。

const post = async () => {
    const voiceboxurl = 'https://voicevox-proto-mggisi6odq-dt.a.run.app/audio_query?speaker=2&text=%20%E3%81%9D%E3%81%86%E3%81%A0%E3%81%AD%EF%BC%81';

    const params = {
        method: "POST"
    }
    const response = await fetch(voiceboxurl, params);

    if (response.ok) {
        const data = await response.json();
        elem.innerHTML = "";
        elem.innerHTML = data.kana;
    } else {
        elem.innerHTML = "失敗";
    }
};

Fiddler で見るとバックエンドは CORS 対応してます。

cors.jpg

デプロイされたフロントエンドからAPIにアクセス

・・・でダメなのは、エラーメッセージよれば応答ヘッダに Access-Control-Allow-Origin が含まれない(上の Fiddler の画像の Response Header で赤枠で囲ったものがない)ということですが、そこを調べてみてください。

1Like

Comments

  1. @terisuke

    Questioner

    ありがとうございました!

    僕もFiddlerを使って同様のものを確認したので、改めて確認したところ同様の出力を得られたので改めてReadmeで確認したところ、
    スクリーンショット 2024-06-19 23.37.28.png

    という部分を見かけて納得が行きました。

    その後engineをDockerHubにダウンロードした後ローカルで起動して http://127.0.0.1:50021/setting に移動、設定を変えて再起動させた上タグづけしてあげ直し、無事CORS問題を解決することができました。

    Fiddlerというツールを使わなければ細かい出力まで確認できなかったので、今日も引き続きコンソールログを見つめる日になるところでした。。。。

    本当にありがとうございました!

  2. 解決したようですのでこのスレッドはクローズ願います。

Your answer might help someone💌