Firebase 云功能,具有对外部 api 的基本身份验证的获取请求

Posted

技术标签:

【中文标题】Firebase 云功能,具有对外部 api 的基本身份验证的获取请求【英文标题】:Firebase cloud function with fetch request with basic auth to external api 【发布时间】:2020-03-03 04:22:59 【问题描述】:

我似乎在从 firebase 云函数中的 fetch 调用中获取预期响应时遇到问题。我确定这是因为我对响应、承诺等如何运作缺乏了解。

我正在尝试将 atlassian crowd 的 rest api 用于 SSO。如果我使用邮递员,我可以从请求中得到想要的结果。所以我知道它的一部分是有效的。

导致我使用云功能的原因是使用 fetch 发出相同的请求会导致来自 localhost 的 CORS 问题。我想如果我可以将浏览器排除在外,那么 CORS 问题就会消失。他们有,但我没有得到想要的回应。

我的云函数如下所示:

const functions = require('firebase-functions');
const fetch = require('node-fetch');
const btoa = require('btoa');
const cors = require('cors')(origin:true);

const app_name = "app_name";
const app_pass = "app_password";

exports.crowdAuthentication = functions.https.onRequest((request, response)=>

    cors(request, response, () =>

        let _uri = "https://my.server.uri/crowd/rest/usermanagement/1/session";
        let _headers = 
            'Content-Type':'application/json',
            'Authorization':`Basic $btoa(`$app_name:$app_pass`)`
        


        let _body = 
            username: request.body.username,
            password: request.body.password
        

        const result = fetch(_uri, 
            method: 'POST',
            headers: _headers,
            body: JSON.stringify(_body),
            credentials: 'include'
        )

        response.send(result);
    )
)

然后我在我的应用程序中使用 fetch 到 firebase 端点进行调用并传递用户名/密码:

fetch('https://my.firebase.endpoint/functionName',
            method: 'POST',
            body: JSON.stringify(username:"myusername",password:"mypassword"),
            headers: 
                'Content-Type':'application/json'
            
        )
        // get the json from the readable stream
        .then((res)=>return res.json();)
        // log the response - size:0, timeout:0
        .then((res)=>
        
            console.log('response: ',res)
        )
        .catch(err=>
        
            console.log('error: ',err)
        )

感谢收看。

【问题讨论】:

您收到哪个错误? @RenaudTarnec 我没有收到错误消息。我收到 cors 类型的响应,正文是 ReadableStream。在其他尝试让这个工作我会收到一个对象size:0, timeout:0,但我有一段时间没有收到了。 【参考方案1】:

2020 年 5 月编辑

请注意,request-promise 已弃用,我建议使用 axios


根据我们在下面的 cmets 中的讨论进行更新

它似乎不适用于 node-fetch 库,您应该使用另一个库,例如 request-promise

因此,您应该如下调整您的代码:

//......
var rp = require('request-promise');


exports.crowdAuthentication = functions.https.onRequest((request, response) => 

    cors(request, response, () => 

        let _uri = "https://my.server.uri/crowd/rest/usermanagement/1/session";
        let _headers = 
            'Content-Type': 'application/json',
            'Authorization': `Basic $btoa(`$app_name:$app_pass`)`
        

        let _body = 
            username: request.body.username,
            password: request.body.password
        

        var options = 
            method: 'POST',
            uri: _uri,
            body: _body,
            headers: _headers,
            json: true
        ;

        rp(options)
            .then(parsedBody => 
                response.send(parsedBody);
            )
            .catch(err => 
                response.status(500).send(err)
                //.... Please refer to the following official video: https://www.youtube.com/watch?v=7IkUgCLr5oA&t=1s&list=PLl-K7zZEsYLkPZHe41m4jfAxUi0JjLgSM&index=3
            );

    );

);

使用节点获取的初始答案

fetch() 方法是异步的,并返回一个 Promise。因此,您需要等待这个 Promise 解决,然后再发回响应,如下所示:

exports.crowdAuthentication = functions.https.onRequest((request, response)=>

    cors(request, response, () =>

        let _uri = "https://my.server.uri/crowd/rest/usermanagement/1/session";
        let _headers = 
            'Content-Type':'application/json',
            'Authorization':`Basic $btoa(`$app_name:$app_pass`)`
        


        let _body = 
            username: request.body.username,
            password: request.body.password
        

        fetch(_uri, 
            method: 'POST',
            headers: _headers,
            body: JSON.stringify(_body),
            credentials: 'include'
        )
        .then(res => 
          res.json()
        )
        .then(json => 
          response.send(json);
        
        .catch(error => 
            //.... Please refer to the following official video: https://www.youtube.com/watch?v=7IkUgCLr5oA&t=1s&list=PLl-K7zZEsYLkPZHe41m4jfAxUi0JjLgSM&index=3
        );
        
    )
)

此外,请注意,您需要使用“Flame”或“Blaze”定价计划。

事实上,免费的“Spark”计划“只允许向 Google 拥有的服务发出出站网络请求”。请参阅https://firebase.google.com/pricing/(将鼠标悬停在“云功能”标题后面的问号上)

【讨论】:

我已经尝试过您之前建议的方法,但没有成功。我刚刚又试了一次,结果一样。我会收到回复,但我无法判断出来自 fetch 的回复。另外 - 我正在使用 Blaze 计划。 我很确定这只是 fetch api 的节点版本。我做了你说的,我仍然得到同样的回应。 显然fetch() 方法返回一个HTTP(S) 响应,它实现了Body 接口。见npmjs.com/package/node-fetch#class-response。我已经用它调整了我的答案,即使你暂时没有成功,这似乎是正确的方法。 你可以试试npmjs.com/package/request-promise。它可以与 Cloud Functions 一起正常工作。 好的,使用正文界面更新后,我现在得到了上面提到的响应,即size:0, timeout:0。所以至少它得到了可读流以外的东西——这是我以前得到的。我可以看看 request-promise。

以上是关于Firebase 云功能,具有对外部 api 的基本身份验证的获取请求的主要内容,如果未能解决你的问题,请参考以下文章

具有 Firebase 云功能的非 Google MySQL 数据库连接

具有实时数据库触发器的 Firebase 云功能:如何更新源节点?

Flutter / Firebase:管理员具有应用内功能或云功能?

使用 Firebase Cloud Functions,我可以从外部 API 安排更新以更新 Firestore

使用 firebase 云功能向非谷歌服务器发送 GET 请求

Firebase 云函数对另一个 Firebase 云函数的 http 请求