在Javascript / jQuery中解码base64文件以供下载

时间:2022-11-03 18:34:08

Today I have been experimenting with SQL binary objects. I started by storing an image in a table, making an AJAX request for a base64 encoding of the image, and displaying it with.

今天我一直在试验SQL二进制对象。我开始将一个图像存储在一个表中,对图像的base64编码进行AJAX请求,然后显示它。

<img src="data:image/jpeg;base64,' + base64imageReturnedWithAjax + '">')

The image displays fine.

图像显示正常。

The web project I'm working on also requires file downloads (PDF, mainly) - great, I thought, I'll store the PDF as a SQL binary object too, collect it from the server in the same way and then somehow magically decode it for download at the other end.

我正在处理的Web项目也需要文件下载(主要是PDF) - 很棒,我想,我也将PDF存储为SQL二进制对象,以相同的方式从服务器收集它然后以某种方式神奇地解码它可以在另一端下载。

Help!

I first tried to decode it using a jQuery base64 decoder (https://github.com/carlo/jquery-base64) with:

我首先尝试使用jQuery base64解码器(https://github.com/carlo/jquery-base64)解码它:

$.base64.decode(base64fileReturnedWithAjax)

This generates the following error in the console:

这会在控制台中生成以下错误:

Uncaught Cannot decode base64
_getbyte64
_decode
$.ajax.success
f.Callbacks.o
f.Callbacks.p.fireWith
w
f.support.ajax.f.ajaxTransport.send.d

My question is, therefore: Is this a feasible way to handle file downloads? if so, how! and if not, is there an advised way to allow a file to be downloaded from a SQL table?

因此,我的问题是:这是处理文件下载的可行方法吗?如果是这样,怎么样!如果没有,是否有建议的方法允许从SQL表下载文件?

Kind regards, ATfPT

亲切的问候,ATfPT


EDIT: If it helps, this is the webmethod that retrieves and sends the file from the db/server (in VB.NET). Fileblob is the binary object within the database.

编辑:如果它有帮助,这是从db / server(在VB.NET中)检索和发送文件的web方法。 Fileblob是数据库中的二进制对象。

    'Having connected to the table
    While lrd.Read()
        Dim fileBytes = CType(lrd("Fileblob"), Byte())
        Dim stream = New MemoryStream(fileBytes, 0, fileBytes.Length)
        Dim base64String = Convert.ToBase64String(stream.ToArray())
        document.Add(base64String)
    End While

    Dim serializer As New JavaScriptSerializer()
    Dim returnVal As String = serializer.Serialize(document)

    Return returnVal

2 个解决方案

#1


4  

Inline base 64 works well with images (as long as they are small), so you are probably on the right track there. However, I don't think you are going down the right path for PDFs or most other blobs (varbinary(max) in SQL Server).

内联基础64适用于图像(只要它们很小),所以你可能在那里正确的轨道。但是,我不认为你正在沿着正确的路径前往PDF或大多数其他blob(SQL Server中的varbinary(max))。

The way I would do this is to create a HTTP handler (Controller, ASHX, ASPX, etc.) which sets the correct HTTP headers and passes the data retrieved from SQL Server to Response.BinaryWrite() as a byte array. This is fast, clean, and reliable. It also requires very little code.

我这样做的方法是创建一个HTTP处理程序(Controller,ASHX,ASPX等),它设置正确的HTTP标头,并将从SQL Server检索到的数据作为字节数组传递给Response.BinaryWrite()。这是快速,清洁和可靠的。它还需要很少的代码。

By comparison, base 64 encoding increases file size, and I'm not aware of any reliable means to process a base 64 string client-side and instruct the browser to open it with the correct application. Plus, the encoding/decoding is completely unnecessary overhead (which may be significant on a large file).

相比之下,base 64编码增加了文件大小,我不知道有任何可靠的方法来处理base 64字符串客户端并指示浏览器使用正确的应用程序打开它。另外,编码/解码完全是不必要的开销(在大文件上可能很重要)。

Incidentally, you could also use a HTTP handler for your images. Or, you could continue you use base 64 but serve all your images in a single JSON object which would reduce your request count (at the expense of more client-processing code).

顺便提一下,您还可以为图像使用HTTP处理程序。或者,您可以继续使用base 64,但在单个JSON对象中提供所有图像,这将减少您的请求数量(以更多客户端处理代码为代价)。

HTTP Handler Example

I stripped down some production code into just the part which handles PDFs. This should work with minimal modification.

我将一些生产代码简化为处理PDF的部分。这应该只需要很少的修改。

Start by adding a Generic Handler to your project in Visual Studio. It will have an ASHX extension.

首先在Visual Studio中为项目添加Generic Handler。它将具有ASHX扩展。

public partial class RequestHandler : IHttpHandler
{
    public void ProcessRequest( HttpContext context ) {
        HttpRequest request = context.Request;
        HttpResponse response = context.Response;

        byte[] bytes = null; // get from your database
        string fileName = null; // get from database or put something generic here like "file.pdf"

        response.ContentType = "application/pdf";
        response.AddHeader( "content-disposition", "inline;filename=" + fileName );
        response.AddHeader( "Content-Length", bytes.Length.ToString() );

        response.Buffer = true;
        response.BinaryWrite( bytes );
        response.Flush();
    }

    public bool IsReusable {
        get {
            return true;
        }
    }
}

To invoke this code, you can simply link to it e.g. <a href="RequestHandler.ashx?id=abc">Download</a>. You can also put this code inside an ASPX page and trigger it in response to a button click, page event, etc.

要调用此代码,您只需链接到该代码,例如下载。您还可以将此代码放在ASPX页面中并触发它以响应按钮单击,页面事件等。

#2


0  

If I follow what your goal is, then the issue isn't with the decoding, it's with the fact that javascript can't trigger a download. This is because it can't send the browser (itself) a content-disposition http header.

如果我遵循你的目标,那么问题不在于解码,而在于javascript无法触发下载。这是因为它无法向浏览器(本身)发送内容处理http标头。

You could do one of the following (that I can think of):

您可以执行以下操作之一(我能想到):

  1. Use a traditional object element to embed the PDF. You could have that get generated dynamically with jquery. And set the object source URL to the data: URI.

    使用传统的对象元素嵌入PDF。您可以使用jquery动态生成。并将对象源URL设置为data:URI。

  2. (This is just a theory), you could use window.location.assign('data:xxx) which would either take the user to the PDF or trigger the download, depending on how PDFs with no content-disposition are handled.

    (这只是一个理论),您可以使用window.location.assign('data:xxx),它可以将用户带到PDF或触发下载,具体取决于处理没有内容处置的PDF的方式。

I'm pretty sure, however, that if an ajax request gets a content-disposition of download in the response header, it will bubble up and the user is presented with the download option, which would eliminate the need for the data schema.

但是,我很确定,如果一个ajax请求在响应头中获得了下载的内容处理,它将会冒出来并向用户提供下载选项,这将消除对数据模式的需求。

#1


4  

Inline base 64 works well with images (as long as they are small), so you are probably on the right track there. However, I don't think you are going down the right path for PDFs or most other blobs (varbinary(max) in SQL Server).

内联基础64适用于图像(只要它们很小),所以你可能在那里正确的轨道。但是,我不认为你正在沿着正确的路径前往PDF或大多数其他blob(SQL Server中的varbinary(max))。

The way I would do this is to create a HTTP handler (Controller, ASHX, ASPX, etc.) which sets the correct HTTP headers and passes the data retrieved from SQL Server to Response.BinaryWrite() as a byte array. This is fast, clean, and reliable. It also requires very little code.

我这样做的方法是创建一个HTTP处理程序(Controller,ASHX,ASPX等),它设置正确的HTTP标头,并将从SQL Server检索到的数据作为字节数组传递给Response.BinaryWrite()。这是快速,清洁和可靠的。它还需要很少的代码。

By comparison, base 64 encoding increases file size, and I'm not aware of any reliable means to process a base 64 string client-side and instruct the browser to open it with the correct application. Plus, the encoding/decoding is completely unnecessary overhead (which may be significant on a large file).

相比之下,base 64编码增加了文件大小,我不知道有任何可靠的方法来处理base 64字符串客户端并指示浏览器使用正确的应用程序打开它。另外,编码/解码完全是不必要的开销(在大文件上可能很重要)。

Incidentally, you could also use a HTTP handler for your images. Or, you could continue you use base 64 but serve all your images in a single JSON object which would reduce your request count (at the expense of more client-processing code).

顺便提一下,您还可以为图像使用HTTP处理程序。或者,您可以继续使用base 64,但在单个JSON对象中提供所有图像,这将减少您的请求数量(以更多客户端处理代码为代价)。

HTTP Handler Example

I stripped down some production code into just the part which handles PDFs. This should work with minimal modification.

我将一些生产代码简化为处理PDF的部分。这应该只需要很少的修改。

Start by adding a Generic Handler to your project in Visual Studio. It will have an ASHX extension.

首先在Visual Studio中为项目添加Generic Handler。它将具有ASHX扩展。

public partial class RequestHandler : IHttpHandler
{
    public void ProcessRequest( HttpContext context ) {
        HttpRequest request = context.Request;
        HttpResponse response = context.Response;

        byte[] bytes = null; // get from your database
        string fileName = null; // get from database or put something generic here like "file.pdf"

        response.ContentType = "application/pdf";
        response.AddHeader( "content-disposition", "inline;filename=" + fileName );
        response.AddHeader( "Content-Length", bytes.Length.ToString() );

        response.Buffer = true;
        response.BinaryWrite( bytes );
        response.Flush();
    }

    public bool IsReusable {
        get {
            return true;
        }
    }
}

To invoke this code, you can simply link to it e.g. <a href="RequestHandler.ashx?id=abc">Download</a>. You can also put this code inside an ASPX page and trigger it in response to a button click, page event, etc.

要调用此代码,您只需链接到该代码,例如下载。您还可以将此代码放在ASPX页面中并触发它以响应按钮单击,页面事件等。

#2


0  

If I follow what your goal is, then the issue isn't with the decoding, it's with the fact that javascript can't trigger a download. This is because it can't send the browser (itself) a content-disposition http header.

如果我遵循你的目标,那么问题不在于解码,而在于javascript无法触发下载。这是因为它无法向浏览器(本身)发送内容处理http标头。

You could do one of the following (that I can think of):

您可以执行以下操作之一(我能想到):

  1. Use a traditional object element to embed the PDF. You could have that get generated dynamically with jquery. And set the object source URL to the data: URI.

    使用传统的对象元素嵌入PDF。您可以使用jquery动态生成。并将对象源URL设置为data:URI。

  2. (This is just a theory), you could use window.location.assign('data:xxx) which would either take the user to the PDF or trigger the download, depending on how PDFs with no content-disposition are handled.

    (这只是一个理论),您可以使用window.location.assign('data:xxx),它可以将用户带到PDF或触发下载,具体取决于处理没有内容处置的PDF的方式。

I'm pretty sure, however, that if an ajax request gets a content-disposition of download in the response header, it will bubble up and the user is presented with the download option, which would eliminate the need for the data schema.

但是,我很确定,如果一个ajax请求在响应头中获得了下载的内容处理,它将会冒出来并向用户提供下载选项,这将消除对数据模式的需求。