如何通过Microsoft Graph API获取附件原始内容并解决编码上传异常
Microsoft Graph API 文件附件获取编码异常、上传损坏问题处理
问题现象
- 调用Graph接口获取邮件文件附件时,返回内容字节存在编码异常,和Notepad++打开的原文件内容完全不匹配,原文件二进制内容片段如下:
UÏMÌØˆ€aX!D"AŠMtPïq¡ª†f24O]J¦¢’k¿ÇFcX+|¿¯÷q”z{CîËC~ãZVŸâÆù ´*ëáµå:ã/•þ57Yü*—kØ&Ž=NDüßÒLó>@÷.MÊ ×núšÙÄlsb´Ò·SFAÙá~˜ wpÌ&—wY¯ÇpÊúé(¯uïû°×Œ†ˆ÷.”ÒB1ŒKŽ|G;m««¼Õ‘h’IRLp°,µ‰<ÿ¥*‡ë>Ž´ÌÇRtA‰öjJäÂY<5&u„óNæÓÓ¿Md¡U§ÎkäÐÁJÛO{9’^¬C]Ó<ô;Ë:N“šK8KÏH1
- 最初使用的附件获取代码返回内容格式完全错误,代码如下:
public function getRawAttachmentContents($emailAddress, $messageId) { return $this->graph->createRequest("GET", "/users/$emailAddress/messages/$messageId/attachments/{attachmentId}") ->setReturnType(get_class(new \Microsoft\Graph\Model\FileAttachment())) ->execute(); }
- 首次尝试在接口路径末尾追加
$value获取原始二进制内容时,接口无任何返回,返回情况截图:
- 调整代码后可获取到和Notepad++打开显示完全一致的附件内容,但将返回内容上传至草稿邮件时,要么无法创建附件,要么接口返回
201 Created响应但生成的附件损坏。可正确获取原始附件内容的代码如下:
public function getRawAttachmentContents($emailAddress, $messageId, $attachmentId) { $attachment = $this->graph->createRequest("GET", "/users/$emailAddress/messages/$messageId/attachments/$attachmentId/\$value") ->execute(); $attachment->getRawBody()->rewind(); $file_contents = $attachment->getRawBody()->getContents(); return $file_contents; }
根因说明
- 未加
$value调用接口时,返回的是JSON结构的附件实体,其中文件内容是Base64编码的contentBytes字段,SDK绑定FileAttachment模型做反序列化时存在编码转换逻辑,会破坏原始二进制字节,导致内容和原文件不一致。 - 初次调用
$value端点无返回,是因为该端点直接返回二进制流,不存在JSON结构化响应,不能通过绑定模型类的方式解析结果,必须直接读取响应的原始Body流。 - 上传附件损坏的核心问题:创建文件附件的接口要求传入的
contentBytes字段为Base64编码的文件内容,直接传入获取到的原始二进制流会导致内容解析错误;若上传时未正确填写附件MIME类型、原文件名,也会出现附件损坏的情况。
正确实现方案
- 附件获取环节直接使用上述调整后的流读取代码,拿到的
$file_contents是原始正确的二进制字节,不要对该内容做任何编码转换、字符集修改操作,避免破坏文件结构。 - 上传附件到草稿邮件时,构造符合接口要求的请求体,对原始字节做Base64编码后传入,示例代码如下:
// 构造附件上传参数 $attachmentPayload = [ "@odata.type" => "#microsoft.graph.fileAttachment", "name" => "原文件完整名称带后缀", // 例如 合同.pdf "contentType" => "文件对应的标准MIME类型", // 例如pdf对应application/pdf,docx对应application/vnd.openxmlformats-officedocument.wordprocessingml.document "contentBytes" => base64_encode($file_contents) // 必须对原始二进制内容做Base64编码 ]; // 发起上传请求 $this->graph->createRequest("POST", "/users/{$emailAddress}/messages/{$draftMessageId}/attachments") ->attachBody($attachmentPayload) ->execute();
内容的提问来源于stack exchange,提问作者BigDataFiles
相关产品推荐
相关产品推荐

