尝试将视频上传到 YouTube 时收到 "Malformed multipart body"

Getting "Malformed multipart body" when trying to upload video to YouTube

我有一个应用程序可以代表我们的客户将视频上传到 YouTube。我们管理着数以千计的频道,每天上传数以千计的视频。这已经工作了多年。代码是用C#、.Net 4.7 编写的(实际上使用的是稍旧的版本,但我不得不更新它以便重新编译和测试)。它使用 REST API(不是 SDK)。

由于某种原因,代码在 2018 年 10 月 12 日星期五晚上崩溃了。我们所有上传 return 状态为 400 且 "Malformed multipart body." 为 body 的请求.

我们至少有 6 个月没有更改代码(尽管可能超过一年)。我能够在我的开发机器上重现错误。我查看了 Fiddler 中的原始 http 请求,但没有发现任何问题,尽管我很难找到普通的 REST 文档来确认 content-disposition headers。我知道 JSON 和视频都很好(我验证了 JSON 并确认我能够将视频直接上传到 YouTube)。此外,我们进行的所有其他 API 调用都可以正常工作。只是上传有问题

这是来自 Fiddler 的 HTTP 请求的副本...

POST https://www.googleapis.com/upload/youtube/v3/videos?part=snippet,status HTTP/1.1
Authorization: Bearer <token>
Content-Type: multipart/form-data; boundary="590ce98e-6411-4e49-8dde-d7aa06cb067d"
Host: www.googleapis.com
Content-Length: 8305362
Expect: 100-continue

--590ce98e-6411-4e49-8dde-d7aa06cb067d
Content-Type: application/json; charset=utf-8
Content-Disposition: form-data; name=json; filename=file.json; filename*=utf-8''file.json

{"snippet":{"title":"77 Wakefield Street, Bald Hills, QLD, 4036","description":"77 Wakefield Street\r\n\r\nContact Brian Brewder for more information.\nTourFactory Corporate Headquarters\n123-456-7890\n\r\n","categoryId":19,"tags":["Tag1","Tag2"]},"status":{"privacyStatus":"public","embeddable":true}}
--590ce98e-6411-4e49-8dde-d7aa06cb067d
Content-Disposition: form-data; name="files"; filename="video"
Content-Type: video/x-msvideo

<video>

API 的 YouTube 端似乎发生了一些变化,但我查看了博客,没有看到任何列出的内容。由于 Google 使用 Whosebug 提供支持,我希望一些body 可以帮助我确定问题。

所以,显然是什么导致了这个问题(现在仍然如此)

Content-Type: multipart/mixed;

不再接受。我通过改变一些东西设法得到一条错误消息,并说只发送 video/*application/octet-stream。不幸的是,虽然我这样做仍然可以从服务器获得 OK,但导致 YouTube 视频损坏

此时我尝试玩 headers 但没有成功。该文件会被 YouTube 接受,但不会正确显示。我怀疑他们更改或删除了 non-resumable 上传 API。如果他们这样做了,我找不到这方面的公告。

所以,我的 "solution" - 嗯,一个解决方法 - 是使用可恢复上传协议重新实现我的上传功能。

https://developers.google.com/youtube/v3/guides/using_resumable_upload_protocol

这行得通并且没花太长时间。只需确保为两个请求设置 X-Upload-Content-Length 和 x-upload-content-type(元数据优先,上传后有效负载 URL)。

所以您首先 POST 相同的元数据(代码段和状态)并获取 PUT url

QByteArray responseLocation = reply->rawHeader( "Location" );

然后使用相同的 X-Upload-Content-Length 和 x-upload-content-type

创建 PUT 请求
newrequest.setRawHeader( "X-Upload-Content-Length", QByteArray::number( video->size() ) );
newrequest.setRawHeader( "x-upload-content-type", "video/*" );

这对我有用 - 希望对您有所帮助!