Google API 带有 Firebase 身份验证的网关:无法将响应返回给客户端

Google API Gateway with Firebase Auth: Unable to get the response back to client

我正在尝试使用 Firebase 身份验证的 GCP API 网关。我可以看到我的请求已从日志中处理并完成,响应代码为 200。但是,我没有将响应返回给我的客户端。当我从客户端和 curl 直接调用函数(通过传递 api 网关)时,我得到了响应。我错过了什么吗?

API 配置

swagger: "2.0"
info:
 title: API Endpoints
 description: API Endpoints
 version: 1.0.1
schemes:
 - https
produces:
 - application/json
securityDefinitions:
 firebase:
   authorizationUrl: ""
   flow: "implicit"
   type: "oauth2"
   x-google-issuer: "https://securetoken.google.com/my-project"
   x-google-jwks_uri: "https://www.googleapis.com/service_accounts/v1/metadata/x509/securetoken@system.gserviceaccount.com"
   x-google-audiences: "my-project"
paths:
 /hello:
   get:
     summary: Test link
     operationId: hello
     x-google-backend:
       address: https://us-central1-my-project.cloudfunctions.net/hello
     security:
       - firebase: []
     responses:
       "200":
         description: A successful response
         schema:
           type: string
       "403":
         description: Failed to authenticate

函数

/**
 * Responds to any HTTP request.
 *
 * @param {!express:Request} req HTTP request context.
 * @param {!express:Response} res HTTP response context.
 */
exports.helloWorld = (req, res) => {
  let message = req.query.message || req.body.message || 'Hello World!';
  console.log("I am here inside the app")
  res.status(200).send(message);
};

来自云函数的日志

其他日志 { insertId: "8c13b49c-2752-4216-8188-d445f4724ef14850908905639612439@a1" jsonPayload: { api_key_state: "NOT CHECKED" api_method: "1.myapi.hello" api_name: "1.myapi" api_version: "1.0.1" client_ip: "999.999.999.999" http_method: "GET" http_response_code: 200 location: "us-central1" log_message: "1.myapi.hello is called" producer_project_id: "myproject" request_latency_in_ms: 161 request_size_in_bytes: 4020 response_size_in_bytes: 579 service_agent: "ESPv2/2.17.0" service_config_id: "myapi-config" timestamp: 1606313914.9804168 url: "/hello" } logName: "projects/myproject/logs/myapi%2Fendpoints_log" receiveTimestamp: "2020-11-25T14:18:36.521292489Z" resource: { labels: { location: "us-central1" method: "1.myapi.hello" project_id: "myproject" service: "myapi" version: "1.0.1" } type: "api" } severity: "INFO" timestamp: "2020-11-25T14:18:34.980416865Z" }

客户端代码 客户端用Flutter - Dart写,用firebase authentication。我没有在此处添加它们,因为它非常标准并且在我的情况下是专有的。

import 'package:flutter/material.dart';
import 'package:dio/dio.dart';

import 'package:example/.env.dart';

final _dio = Dio();

class GetAPIWidget extends StatefulWidget {
  const GetAPIWidget({Key key}) : super(key: key);

  @override
  _GetAPIWidgetState createState() => _GetAPIWidgetState();
}

class _GetAPIWidgetState extends State<GetAPIWidget> {
  String text = 'No response yet';
  @override
  void initState() {
    // TODO: implement initState
    getAPIResponse(endpoint: 'hello').then((value) {
      setState(() {
        text = value.toString();
      });
    }).catchError((onError) {
      setState(() {
        text = onError.toString();
      });
    });
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Text(text),
      ),
    );
  }
}

Future<Map<String, dynamic>> getAPIResponse({
  /// Endpoint to our internal API Gateway. For this option to work url should be null
  String endpoint,
  Map<String, dynamic> queryParameters,
  Map<String, dynamic> headers,
}) async {
  try {
    final Response response = await _dio.get<Map<String, dynamic>>(
      '$api_gateway/$endpoint',
      queryParameters: queryParameters ?? <String, dynamic>{},
      options: Options(
          // receiveTimeout: 20,
          responseType: ResponseType.json,
          contentType: Headers.jsonContentType,
          headers: headers ??
              <String, dynamic>{
                Headers.contentTypeHeader: Headers.jsonContentType,
                Headers.acceptHeader: Headers.jsonContentType,
                'Authorization': 'Bearer ${idToken from firebase auth}',
              }),
    );
    print(response.statusCode);
    print(response.data);
    if (response.statusCode == 200) {
      return response.data;
    } else {
      throw response.statusMessage;
    }
  } on DioError catch (e) {
    if (e.type == DioErrorType.CONNECT_TIMEOUT) {
      throw ('Connection Timeout');
    }
    if (e.type == DioErrorType.RECEIVE_TIMEOUT) {
      throw ('Session Timeout');
    }
  }
  return <String, dynamic>{};
}

客户端 returned {} 这是默认的 return 消息。客户端日志中均未显示任何打印件。

无法正常工作,因为响应中缺少 header。

res.setHeader('Content-Type', 'application/json');