AJAX中Byte[]返回数据类型问题:控制器返回byte[]但AJAX调用失败
Let's break down why your current setup is failing and walk through the correct approach to handle PDF downloads via AJAX.
The Core Issues
- Incorrect Controller Return Type: Using
JsonResultto return abyte[]is not ideal. JSON serialization converts the byte array into a huge array of integers, which is inefficient to transfer and hard for the frontend to parse back into a valid PDF. - Mismatched AJAX Data Type: You've set
dataType: 'json', but the controller is sending raw byte data (or a serialized integer array) instead of valid JSON, so AJAX can't parse it and triggers the error callback. - Suboptimal Binary Data Handling: GET requests have length limits, and default AJAX settings don't handle binary blobs correctly out of the box.
Step 1: Fix the Controller Code
Instead of JsonResult, use FileContentResult to directly return the PDF binary stream with the correct MIME type. This is the standard way to serve files from an ASP.NET controller.
public FileContentResult GeneratePDF(string orderQuoteId) { byte[] pdfData = ServiceCall(); // Return the PDF with appropriate MIME type and optional download filename return File(pdfData, "application/pdf", $"OrderQuote_{orderQuoteId}.pdf"); }
This tells the browser exactly what type of content it's receiving and suggests a filename for download.
Step 2: Update the AJAX Call
Modify your AJAX to handle binary blob data instead of JSON, and adjust settings to match the controller's response:
$.ajax({ url: '@Url.Action("GeneratePDF", "AccountDetail")', type: 'POST', // Use POST if your PDF is large (avoids GET length limits); GET works for small files contentType: 'application/x-www-form-urlencoded; charset=utf-8', // Standard for form data data: { 'orderQuoteId': orderQuoteId }, xhrFields: { responseType: 'blob' // Critical: tells AJAX to expect binary blob data }, success: function (pdfBlob) { // Create a temporary download link to trigger the browser's PDF download const downloadUrl = window.URL.createObjectURL(pdfBlob); const link = document.createElement('a'); link.href = downloadUrl; // Use the filename from the controller, or set your own link.download = `OrderQuote_${orderQuoteId}.pdf`; document.body.appendChild(link); link.click(); // Clean up to free browser resources window.URL.revokeObjectURL(downloadUrl); document.body.removeChild(link); alert('PDF generated successfully!'); }, error: function (xhr, status, error) { // Log details for debugging console.error('PDF Generation Error:', status, error); alert('Error occurred while creating PDF'); } });
Key Explanations
responseType: 'blob': Ensures jQuery doesn't try to parse the response as JSON, which would fail with binary data.FileContentResult: Properly sets HTTP headers (likeContent-TypeandContent-Disposition) that browsers understand for file downloads.- Blob Handling: Converts the binary response into a downloadable file using browser APIs, which is the reliable way to handle PDFs in the frontend.
Alternative: If You Must Use JSON (Not Recommended)
If for some reason you need to stick with returning JSON, you can convert the byte array to a Base64 string in the controller and parse it back to a blob in the frontend. This is less efficient but works:
Controller Code
public JsonResult GeneratePDF(string orderQuoteId) { byte[] pdfData = ServiceCall(); string base64Pdf = Convert.ToBase64String(pdfData); return Json(base64Pdf); }
AJAX Code
$.ajax({ url: '@Url.Action("GeneratePDF", "AccountDetail")', type: 'GET', contentType: 'application/json; charset=utf-8', dataType: 'json', data: { 'orderQuoteId': orderQuoteId }, success: function (base64Result) { // Convert Base64 string back to byte array and blob const byteChars = atob(base64Result); const byteNumbers = new Array(byteChars.length); for (let i = 0; i < byteChars.length; i++) { byteNumbers[i] = byteChars.charCodeAt(i); } const byteArray = new Uint8Array(byteNumbers); const pdfBlob = new Blob([byteArray], { type: 'application/pdf' }); // Same download logic as before const downloadUrl = window.URL.createObjectURL(pdfBlob); const link = document.createElement('a'); link.href = downloadUrl; link.download = `OrderQuote_${orderQuoteId}.pdf`; document.body.appendChild(link); link.click(); window.URL.revokeObjectURL(downloadUrl); document.body.removeChild(link); alert('PDF generated successfully!'); }, error: function () { alert('Error occurred while creating PDF'); } });
But again, the first approach (using FileContentResult and blob response) is the standard, efficient way to handle file downloads.
内容的提问来源于stack exchange,提问作者Beginer

