You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

R Plumber生成可下载Excel文件失败,请求排查问题

Fix: Plumber POST Endpoint Returning Corrupted Excel File

Let's break down what's causing the garbled response and unopenable Excel file in your code, then fix it step by step:

Key Issues in Your Original Code

  1. Conflicting Serialization Logic: You’re using both the @serializer contentType annotation and include_file() in the same endpoint. This creates a conflict—include_file() already handles setting the correct Content-Type header automatically, while the extra serializer annotation can corrupt the binary Excel data by forcing text-based serialization.
  2. Incorrect HTTP Method: Your requirement specifies a POST endpoint, but you’re using @get/excel. While this might not directly cause corruption, it will fail if clients try to send POST requests.
  3. Missing Download Header: Without a Content-Disposition header, your browser treats the binary Excel data as plain text (hence the garbled output) and doesn’t prompt for a download. Saved files also lack proper metadata for Excel to recognize the format.
  4. Risk of File Name Collisions: Using a fixed filename in tempdir() could cause conflicts if multiple requests are processed at the same time.

Corrected Code (Option 1: Using include_file() without extra serializer)

# Load required packages
library(plumber)
library(xlsx) # Or use openxlsx (pure R, no Java dependency)

#* @post /excel  # Match your POST requirement
function(req, res) {
  # Create a unique temporary Excel file to avoid collisions
  temp_excel <- tempfile(fileext = ".xlsx")
  
  # Write your data to the temp file (replace iris with your xlsx_df if needed)
  write.xlsx2(iris, temp_excel, row.names = FALSE)
  
  # Tell the browser to download this as a named Excel file
  res$setHeader(
    "Content-Disposition", 
    'attachment; filename="Output_File.xlsx"'
  )
  
  # Return the file with correct content type
  include_file(
    temp_excel, 
    res, 
    contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
  )
}

Corrected Code (Option 2: Return raw binary data with serializer)

If you prefer to handle the binary read yourself, you can use the serializer annotation without include_file():

library(plumber)
library(xlsx)

#* @post /excel
#* @serializer contentType list(type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
function(req, res) {
  temp_excel <- tempfile(fileext = ".xlsx")
  write.xlsx2(iris, temp_excel, row.names = FALSE)
  
  res$setHeader(
    "Content-Disposition", 
    'attachment; filename="Output_File.xlsx"'
  )
  
  # Read and return the raw binary content of the file
  readBin(temp_excel, "raw", file.info(temp_excel)$size)
}

Bonus: Use openxlsx Instead of xlsx

The xlsx package relies on Java, which can cause environment issues. For a more stable, pure-R alternative, switch to openxlsx:

library(plumber)
library(openxlsx)

#* @post /excel
function(req, res) {
  temp_excel <- tempfile(fileext = ".xlsx")
  write.xlsx(iris, temp_excel, rowNames = FALSE)
  
  res$setHeader(
    "Content-Disposition", 
    'attachment; filename="Output_File.xlsx"'
  )
  
  include_file(
    temp_excel, 
    res, 
    contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
  )
}

Why This Works

  • No more serialization conflicts: We either use include_file() (with auto Content-Type handling) or the serializer annotation with raw binary data—never both.
  • The Content-Disposition header triggers a download prompt in the browser, preventing garbled text display and ensuring the file has the correct extension.
  • tempfile() generates a unique filename every time, eliminating race conditions from concurrent requests.

内容的提问来源于stack exchange,提问作者Zakir Hussain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 08:22:36