通过Ajax发送PDF文件出现空白文件问题
解决办法:用JS/jQuery给ASP.NET MVC服务器发PDF(不用多部分表单)
我明白你现在的困境——不能改服务器代码,还得绕过多部分表单,把PDF以二进制字符串的方式发过去,但现在上传后文件是空的。别担心,咱们对着服务器的接收逻辑来调整前端代码就行:
第一步:先把PDF文件读成原始二进制数据
首先得用FileReader把文件读成ArrayBuffer,这样能完整保留PDF的二进制内容,不会乱码:
// 给文件选择框绑定change事件 $('#fileInput').on('change', function(e) { const selectedFile = e.target.files[0]; // 先校验是不是PDF if (!selectedFile || selectedFile.type !== 'application/pdf') { alert('麻烦选个PDF文件哦'); return; } const reader = new FileReader(); reader.onload = function(event) { // 拿到文件的ArrayBuffer原始数据 const fileBuffer = event.target.result; // 调用发送函数 sendPDFToServer(fileBuffer, selectedFile.name); }; // 以ArrayBuffer格式读取文件 reader.readAsArrayBuffer(selectedFile); });
第二步:把二进制数据正确发给服务器
这里的关键是不让jQuery乱处理你的数据,还要设置对请求头。分两种情况,看服务器预期接收的是原始二进制还是二进制字符串:
情况1:服务器接收原始二进制流
如果服务器是直接读请求流的,就这么写:
function sendPDFToServer(fileBuffer, fileName) { // 把ArrayBuffer转成Blob,保持PDF的MIME类型 const pdfBlob = new Blob([fileBuffer], { type: 'application/pdf' }); $.ajax({ url: '/Home/Upload', // 换成你自己的上传Action地址 type: 'POST', data: pdfBlob, // 绝对不能让jQuery处理数据,否则二进制会被破坏 processData: false, // 设置正确的MIME类型,告诉服务器这是PDF contentType: 'application/pdf', // 如果服务器需要文件名,用自定义请求头传过去 headers: { 'X-File-Name': fileName }, success: function(res) { alert('上传成功啦!'); console.log(res); }, error: function(xhr, status, err) { alert('上传失败了:' + err); console.error('出错详情:', xhr, status, err); } }); }
情况2:服务器明确要二进制字符串
如果服务器必须要二进制字符串格式,那得把ArrayBuffer转成二进制字符串,还要设置对应的字符集:
// 先写个转换函数:把ArrayBuffer转成二进制字符串 function bufferToBinaryString(buffer) { const uint8Arr = new Uint8Array(buffer); let binaryStr = ''; for (let i = 0; i < uint8Arr.length; i++) { binaryStr += String.fromCharCode(uint8Arr[i]); } return binaryStr; } // 发送函数改成这样 function sendPDFToServer(fileBuffer, fileName) { const binaryStr = bufferToBinaryString(fileBuffer); $.ajax({ url: '/Home/Upload', type: 'POST', data: binaryStr, processData: false, // 关键:用x-user-defined字符集,保证二进制字符串不被转码 contentType: 'text/plain; charset=x-user-defined', headers: { 'X-File-Name': fileName }, success: function(res) { alert('上传成功!'); }, error: function(xhr, status, err) { alert('上传失败:' + err); } }); }
几个必须注意的点
processData: false:这个一定要加!不然jQuery会自动把你的二进制数据转成URL编码的字符串,直接把文件内容搞坏,上传后就是空白。contentType:必须和服务器预期的类型匹配,乱设的话服务器读不懂内容。- 别手动编码:绝对不要自己把二进制数据转成base64(除非服务器明确要),不然服务器接收后解析不出来,文件还是空的。
顺便提下服务器的接收逻辑(供你参考)
虽然你不能改服务器,但可以确认下它的Action是不是这么写的(如果是,上面的代码就完全匹配):
[HttpPost] public ActionResult Upload() { // 从自定义头拿文件名 var fileName = Request.Headers["X-File-Name"]; var savePath = Server.MapPath("~/Uploaded/" + fileName); // 直接把请求流写到文件里 using (var fileStream = new FileStream(savePath, FileMode.Create)) { Request.InputStream.CopyTo(fileStream); } return Json(new { success = true }); }
按这个写法来,上传后的PDF就不会是空的啦!
内容的提问来源于stack exchange,提问作者My Helper
相关产品推荐
相关产品推荐

