为啥只有在部署到 Firebase 时才会在 Node.js 和 Angular 之间出现 CORS 错误?

Posted

技术标签:

【中文标题】为啥只有在部署到 Firebase 时才会在 Node.js 和 Angular 之间出现 CORS 错误?【英文标题】:Why do I get a CORS error between Node.js and Angular only when deployed to Firebase?为什么只有在部署到 Firebase 时才会在 Node.js 和 Angular 之间出现 CORS 错误? 【发布时间】:2021-09-27 12:50:25 【问题描述】:

错误:Access to XMLHttpRequest at 'https://us-central1-yalebot-n9xq.cloudfunctions.net/dialogflowGateway' from origin 'https://yalebot-n9xq.web.app' 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.

在本地主机上运行或通过 ngrok 暴露在本地运行的 webhook 时,我没有出错。

credentialsmethods 字段添加到cors 没有任何作用。

节点(index.js):

const functions = require("firebase-functions");

// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require("firebase-admin");
const serviceAccount = require("./service-account.json");
const cors = require('cors')(origin:true,
                              credentials:true,
                                methods: 'POST,GET,PUT,OPTIONS,DELETE');
const  SessionsClient  = require('dialogflow');

// admin.initializeApp(
//   credential: admin.credential.cert(serviceAccount),
//   databaseURL: "https://yalebot-n9xq-default-rtdb.firebaseio.com"
// );

// var db = admin.firestore();

//Endpoint that Joins FrontEnd and Dialogflow API
exports.dialogflowGateway = functions.https.onRequest((request, response) => 
    cors(request, response, async () => 
   
        const  queryInput, sessionId  = request.body;
        console.log("Gateway");
        const sessionClient = new SessionsClient( credentials: serviceAccount );
        const session = sessionClient.sessionPath('yalebot-n9xq', sessionId);

        const responses = await sessionClient.detectIntent( session, queryInput);

        const result = responses[0].queryResult;

        response.header('Access-Control-Allow-Origin', "*");
        response.header('Access-Control-Allow-Headers', true);
        response.header('Access-Control-Allow-Credentials', 'Content-Type');
        response.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');

        response.send(result);
    );
); 

const  WebhookClient  = require('dialogflow-fulfillment');


//Path from DialogflowAPI to Further Processsing
exports.dialogflowWebhook = functions.https.onRequest(async (request, response) =>

    response.header('Access-Control-Allow-Origin', "*");
    response.header('Access-Control-Allow-Headers', true);
    response.header('Access-Control-Allow-Credentials', 'Content-Type');
    response.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');

    console.log('Webhook');

    const agent = new WebhookClient( request, response );
    const result = request.body.queryResult;

    async function fallbackHandler(agent)
        agent.add("I do not understand the words that are coming out of your mouth.");
    

    let intentMap = new Map();
    intentMap.set('Default Fallback Intent', fallbackHandler);
    agent.handleRequest(intentMap); 
);

Component.ts(发布请求的地方)

import  Component, OnInit, ChangeDetectionStrategy from '@angular/core';
import  HttpClient  from '@angular/common/http';

const dialogflowUrl = "https://us-central1-yalebot-n9xq.cloudfunctions.net/dialogflowGateway"

@Component(
  selector: 'app-chatbot',
  templateUrl: './chatbot.component.html',
  styleUrls: ['./chatbot.component.scss'],

  changeDetection: ChangeDetectionStrategy.OnPush,
)

export class ChatbotComponent implements OnInit 

  messages = Array();
  loading = false;
  
  // Random ID to maintain session with server
  sessionId = Math.random().toString(36).slice(-5);

  constructor(private http: HttpClient)  

  ngOnInit() 
    this.addBotMessage("Hi. I'm MyChatBot. Let's talk about HIV testing.  Respond by typing to say which topic you want to learn more about. PrEP, Get Self-Testing Kits, Learn about Self-Testing, HIV Testing (in general)");
  

  handleUserMessage(event:any) 
    const text = event.message;
    this.addUserMessage(text);

    this.loading = true;

    // Make the request 
    this.http.post<any>(
      dialogflowUrl,
      
        sessionId: this.sessionId,
        queryInput: 
          text: 
            text,
            languageCode: 'en-US'
          
        
      
    )
    .subscribe(res => 
      const  fulfillmentText  = res;
      this.addBotMessage(fulfillmentText);
      this.loading = false;
    );
  

  addUserMessage(text:string) 
    this.messages.push(
      text,
      sender: 'You',
      reply: true,
      date: new Date()
    );
  

  addBotMessage(text:string) 
    this.messages.push(
      text,
      sender: 'ZhaoBot',
      date: new Date()
    );
  


【问题讨论】:

【参考方案1】:

事实证明,还必须在 Dialogflow 中设置 Access-Control-Allow-Origin 标头。

有一个选项可以在您指定 webhook 的 url 的下方设置字段。

部署到 Firebase 的 Node JS 和 DialogFlow 都算作“服务器”对我来说并不明显。

【讨论】:

以上是关于为啥只有在部署到 Firebase 时才会在 Node.js 和 Angular 之间出现 CORS 错误?的主要内容,如果未能解决你的问题,请参考以下文章

为啥只有在 Windows 控制台程序中按 Ctrl+Z 时才会终止输入? [复制]

为啥我的网站的谷歌地图部分只有在用户删除他/她的 cookie 时才会更新?

为啥只播放 UNNotificationSound 的前 5 秒

为啥只有当我覆盖它时,我的 UINavigtionController 栏才会在 iOS 7 上错误地定位? [复制]

为啥有些字段只有在调试模式激活时才可见?

为啥我的搜索结果只有在我开始输入后才会显示?