首页 > 解决方案 > PubSub 上的 Http 400 推送到云运行

问题描述

我目前正在尝试在 GCP 中构建一个简单的文件(仅限 csv)处理系统,基本上它所做的只是在上传新文件时,代码对其进行解析并将其存储在数据库中。

我使用这些命令创建了一个新主题(文件上传)和一个新服务帐户(按照以下步骤操作:https ://cloud.google.com/run/docs/tutorials/pubsub#integrating-pubsub ):

gcloud projects add-iam-policy-binding my-project \
     --member=serviceAccount:service-0000000000@gcp-sa-pubsub.iam.gserviceaccount.com \
     --role=roles/iam.serviceAccountTokenCreator
   
gcloud iam service-accounts create cloud-run-pubsub-invoker \
   --display-name "Cloud run PubSub Invoker"
   
gcloud run services add-iam-policy-binding myservice \
   --member=serviceAccount:cloud-run-pubsub-invoker@my-project.iam.gserviceaccount.com \
   --role=roles/run.invoker

然后创建订阅:

gcloud pubsub subscriptions create file-upload-sub --topic file-upload \
   --push-endpoint=https://myservice-myurl.a.run.app/api/test/ \
   --push-auth-service-account=cloud-run-pubsub-invoker@my-project.iam.gserviceaccount.com

我有一个存储桶,并使用以下命令将“OBJECT_FINALIZE”事件绑定到它: gsutil notification create -t file-upload -f json -e OBJECT_FINALIZE gs://MyBucket

我的端点具有以下路由(注意:它是部署在云上运行的 docker 映像中的 .net 应用程序):

    [Route("api/[controller]")]
    [ApiController]
    public class TestController : ControllerBase
    {
        //GET : api/test
        [HttpGet]
        public IActionResult Get()
        {
            return Ok($"Get route pinged{Environment.NewLine}");
        }

        //POST : api/test
        [HttpPost]
        public IActionResult Post([FromBody] string bodyContent)
        {
            return Ok($"Content received : {bodyContent}{Environment.NewLine}");
        }
    }

当我使用 curl 命令发送请求时: curl https://myservice-myurl.a.run.app/api/test/ -H "Authorization: Bearer $(gcloud auth print-identity-token)" -H "Content-Type: application/json" -d '"data"'

一切正常(我在控制台和日志查看器中收到确认)但是当我尝试使用 将消息直接推送到主题时gcloud pubsub topics publish file-upload --message '"test"',我在日志查看器中只收到 400 个响应,没有有效负载向我解释它在哪里中断

编辑: 显然这是与我尝试测试应用程序的方式相关的问题,出于某种原因,当消息是基本字符串时,PubSub 转换了将消息发送到云运行的方式,因此它破坏了 .net 内容验证。我更改了代码以接受参数中文件的元数据,一切正常

编辑2: 写了一个正确的答案来解释我错在哪里

标签: .netgoogle-cloud-platformgoogle-cloud-pubsubgoogle-cloud-run

解决方案


正如我原始帖子的评论中所指出的,我正在写一个正确的答案来解释我错在哪里:

PubSub 发送的数据结构与 curl 不同,因此当我尝试读取收到的数据时,云运行响应 400 错误,因为 .net json 到对象验证失败。

起初,我以为 pub sub 只是将元数据文件发送到云运行,事实并非如此。PubSub 以如下所示的结构发送文件信息:

    public class Body
    {
        public Message Message { get; set; }

        public Body()
        {
            
        }
    }

    public class Message
    {
        public string MessageId { get; set; }
        public string PublishTime { get; set; }
        public string Data { get; set; }

        public Message()
        {
            
        }

        public Message(string messageId, string publishTime, string data)
        {
            MessageId = messageId;
            PublishTime = publishTime;
            Data = data;
        }
    }

因此,当我通过使用 curl 发送基本字符串来测试我的代码时,一切正常,而当我尝试直接在主题中编写消息时却没有。仅仅是因为数据结构。

我为此更改了代码:

        public IActionResult Post([FromBody] Body body)
        {
            var base64EncodedBytes = Convert.FromBase64String(body.Message.Data);
            var readableContent = Encoding.UTF8.GetString(base64EncodedBytes);

            var fileMetadata = JsonConvert.DeserializeObject<FileMetadata>(readableContent);

            var accounts = new List<Account>();

            try
            {
                accounts = CsvParser.Parse(fileMetadata.name);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }

            Console.WriteLine($"{accounts.Count} account(s) detected in csv file");

            return Ok();
        }

推荐阅读