.net - 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: 写了一个正确的答案来解释我错在哪里
解决方案
正如我原始帖子的评论中所指出的,我正在写一个正确的答案来解释我错在哪里:
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();
}
推荐阅读
- vba - 十进制输入值
- spring - 使用jar文件运行时的Spring Boot thymeleaferror
- jquery - 如何在单个 JQuery 函数中使用多个 -web-kit 过滤器?
- cordova - Ionic Cordova 占位符闪屏仍然出现
- javascript - Nuxt.js/Vue.js 可重用模态
- java - Kotlin FXML 文件控制器
- laravel - “雄辩的方式”:如果没有找到模型,则放弃 where 约束
- python-3.x - 使用 Selenium 和 python 打开页面上的所有加号按钮
- postgresql - 有没有更好的方法来更新 PostgreSQL
- amazon-web-services - 如何在 CloudFormation YAML 模板中为 CloudWatch 日志设置保留?