如何在 Graphql 突变中返回 PDF 文件?
Posted
技术标签:
【中文标题】如何在 Graphql 突变中返回 PDF 文件?【英文标题】:How to return PDF file in an Graphql mutation? 【发布时间】:2020-07-27 18:46:26 【问题描述】:我在前端使用 React 和 Graphql,在后端使用 Django 和 Graphene。
我希望能够下载报告的 pdf 文件。我尝试使用 mutation 来做到这一点,如下所示:
const [createPdf, loading: createPdfLoading, error: createPdfError] = useMutation(CREATE_PDF)
const handleCreatePDF = async (reportId) =>
const res = await createPdf(variables: reportId: parseInt(reportId) )
debugger;
;
export const CREATE_PDF = gql`
mutation ($reportId: Int!)
createPdf (reportId: $reportId)
reportId
`;
在后端我有这样的东西:
class CreatePDFFromReport(graphene.Mutation):
report_id = graphene.Int()
class Arguments:
report_id = graphene.Int(required=True)
def mutate(self, info, report_id):
user = info.context.user
if user.is_anonymous:
raise GraphQLError("You are not logged in!")
report = Report.objects.get(id=report_id)
if not report:
raise GraphQLError("Report not found!")
if user != report.posted_by:
raise GraphQLError("You are not permitted to do that!")
html_string = render_to_string('report.html', 'report_id': 1)
pdf_file = HTML(string=html_string)
response = HttpResponse(pdf_file, content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="rapport_"'.format(report_id)
return response
# return CreatePDFFromReport(report_id=report_id)
当我取消注释 return CreatePDFFromReport(report_id=report_id)
时,它工作正常。
但我想返回 pdf 文件。
有没有可能这样做?
谢谢。
【问题讨论】:
@xadm 最好的方法是什么?将其添加为答案,我会接受。 【参考方案1】:仅靠变异是不行的。
您不能使用 json'ed 通信返回文件(二进制)/标题(mime)/等(需要被浏览器作为下载请求行为处理)。 GraphQL 请求和响应都是 json 格式。
解决方案
工作流程:
调用突变(在变量中传递参数) 解析器创建文件内容并将其保存在某处(服务器或 s3 上的文件存储) 解析器返回一个文件id
作为下载网址的一部分或完整的url
(字符串)到目标文件
id
或 url
在这种情况下应该是所需突变响应的一部分
mutation ($reportId: Int!)
createPdf (reportId: $reportId)
reportDownloadId
突变结果(以及我们的reportDownloadId
)在data
中可用
可以通过两种方式访问来自突变的data
(结果/响应):
... data
:
const [addTodo, data ] = useMutation(ADD_TODO);
...或onCompleted
处理程序:
addTodo(
variables: type: input.value ,
onCompleted = (data) =>
// some action with 'data'
// f.e. setDownloadUrl(data.reportDownloadId)
// from 'const [downloadUrl, setDownloadUrl] = useState(null)'
);
docs中描述了这两种方法
这两种方法都允许您(有条件地)呈现下载按钮/链接/组件,f.e.
downloadUrl && <DownloadReport url=downloadUrl/>
downloadUrl && <a href=downloadUrl>Report ready - download it</a>
// render download, share, save in cloud, etc.
Handler方法可用于自动调用下载文件请求,无需渲染额外的按钮。这个看起来像一个动作,而从技术上讲有两个请求(graphql 突变和下载)。这个thread 描述了如何使用 js 处理下载。
【讨论】:
【参考方案2】:您可以将 PDF 编码为 Base64 并将其作为字符串发送。 然后在前端解码。
注意Base64每3个字节使用4个字节编码(3MB文件变成4MB字符串)。
【讨论】:
当然,但要多 33% ... 适合嵌入图标、svg、小文件 ... 或小规模的方法以上是关于如何在 Graphql 突变中返回 PDF 文件?的主要内容,如果未能解决你的问题,请参考以下文章