小鸟游六花 發表於 2024-6-14 11:16:00

Angular 集成 StreamSaver 大文件下载

<p>应用场景:</p>
<p>实现目标: 在网页端实现大文件(文件大小 &gt;= 2 G) 断点续传</p>
<p>实际方案: 发送多次请求, 每次请求一部分文件数据, 然后通过续写将文件数据全部写入.</p>
<p>难点: 无法实现文件续写, 最后采用&nbsp;StreamSaver 来解决这个问题.</p>
<p>&nbsp;</p>
<p>1. 首先从 git hub 将&nbsp;StreamSaver 拉取下来.</p>
<p>StreamSaver&nbsp;gitHub 项目地址:&nbsp;GitHub - jimmywarting/StreamSaver.js: StreamSaver writes stream to the filesystem directly asynchronous</p>
<p>(这里推荐使用将 StreamSaver.js 文件直接放到项目中, 因为 StreamSaver 的实现需要借助已授信 https 服务器,</p>
<p>如果不配置自己的&nbsp;https 服务器, 会访问 StreamSaver.js 默认已授信 https 服务器, 来实现下载功能</p>
<p>如果使用的是自签名的 https 服务器, 需要将证书安装在用户电脑或用户浏览器端进行一些配置才可正常使用, 稍后会讲到)</p>
<p>&nbsp;</p>
<p>2.将 js 库导入 Angular 项目, 能在 ts 文件中调用 js 库的函数, 变量.</p>
<p>2.1 将&nbsp;StreamSaver.js 文件放在 Angular 项目&nbsp;assets\utils-js 目录下</p>
<p><img src="https://img2024.cnblogs.com/blog/3207251/202406/3207251-20240614091729130-1498494581.png"></p>
<p>&nbsp;</p>
<p>&nbsp;2.2 然后在&nbsp;index.html 的&nbsp;head 标签中添加脚本, 如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">head</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span><span style="color: rgba(0, 0, 0, 1)">
    ... 其他代码
    </span><span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">script </span><span style="color: rgba(255, 0, 0, 1)">type</span><span style="color: rgba(0, 0, 255, 1)">="text/javascript"</span><span style="color: rgba(255, 0, 0, 1)"> src</span><span style="color: rgba(0, 0, 255, 1)">="assets/utils-js/StreamSaver.js"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">script</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">head</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span></pre>
</div>
<p>&nbsp;</p>
<p>2.3 随后在要使用&nbsp;StreamSaver.js 的 ts 文件中声明</p>
<p>file-handle.ts</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">declare const streamSaver: any;
export class FileHandle {
  static createWrite(fileName: string) {
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> (!fileName) <span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Error('文件名不能为空'<span style="color: rgba(0, 0, 0, 1)">);
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 如果没有自己已授信的 https 服务器, 下面 streamSaver.mitm = 'https://xxx_ip:xxx_port/other/mitm.html?version=2.0.0'; 可删除. </span>
    <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 会走默认服务器: https://jimmywarting.github.io/StreamSaver.js/mitm.html?version=2.0.0</span>
    streamSaver.mitm = 'https://xxx_ip:xxx_port/other/mitm.html?version=2.0.0'<span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 创建一个可写流</span>
    <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> streamSaver.createWriteStream(fileName).getWriter();
  }
}</span></pre>
</div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<div>
<p>补充: 如果使用 npm 安装使用&nbsp;streamsaver, 在配置另外授信的 https 服务器的时候, ts 会报错, 所以最好还是将&nbsp;StreamSaver.js 文件直接放到项目中使用.</p>
<p>import * as streamSaver from 'streamsaver';</p>
<p>streamSaver.mitm = 'https://xxx_ip:xxx_port/other/mitm.html?version=2.0.0';&nbsp;</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">npm i streamsaver

npm i @types</span>/streamsaver</pre>
</div>
<p>&nbsp;</p>
3. 使用&nbsp;streamSaver 完成下载</div>
<div>
<div class="cnblogs_code">
<pre>download = () =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
    const writer </span>=<span style="color: rgba(0, 0, 0, 1)"> FileHandle.createWrite();
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 伪代码</span>
    <span style="color: rgba(0, 0, 255, 1)">for</span>(let i = 0; i++; i &lt;= 10<span style="color: rgba(0, 0, 0, 1)">) {
      </span><span style="color: rgba(0, 0, 255, 1)">this</span>.http.post('/download', ...).subscribe(next =&gt;<span style="color: rgba(0, 0, 0, 1)"> {
            writer.write(next);
      });
    }
    write.end();
}</span></pre>
</div>
<p>&nbsp;</p>
<p>4. 如果下载文件不想借助 StreamSaver 默认的 https 服务器, 需要在 nginx 服务器进行如下配置</p>
<p>注意:&nbsp;</p>
<pre>nginx 配置的 "other" 路由应当和代码中的 streamSaver.mitm = 'https://xxx_ip:xxx_port/other/mitm.html?version=2.0.0'<span>; 对应起来</span></pre>
</div>
<div>
<div class="cnblogs_code">
<pre># https
server {
    listen        9999ssl;
    listen[::]:9999 ssl;
    server_name    0.0.0.0;

    ssl_certificate   /etc/nginx/my-ssl/sss.crt; # crt
    ssl_certificate_key /etc/nginx/my-ssl/sss.key; # key

    ssl_session_cache   shared:SSL:1m;
    ssl_session_timeout 5m;


        ssl_protocols TLSv1.3;
    ssl_ciphers 'HIGH:!aNULL:!MD5 or HIGH:!aNULL:!MD5:!3DES';
    ssl_prefer_server_ciphers on;

    location / {
      root   /fornt/my-app;
      indexindex.html index.htm;
      try_files $uri $uri/ /index.html;
    }

    location ^~/api {
      proxy_pass https://127.0.0.1:8888;
    }

    location ^~/other/mitm.html {
          alias   /streamsaver/mitm.html;
    }
    location ^~/other/sw.js {
      alias   /streamsaver/sw.js;
    }
    location ^~/other/ping {
      alias   /streamsaver/sw.js;
    }

}   </pre>
</div>
</div>
<div>将&nbsp;mitm.html 和&nbsp;sw.js 文件放到 nginx 服务器&nbsp; /streamsaver 目录下</div>
<div>
<p><img src="https://img2024.cnblogs.com/blog/3207251/202406/3207251-20240614110629920-3380606.png"></p>
<p>最后重启 nginx , 就将授信 https 服务器改为了自己的服务器.</p>
<p>&nbsp;如果使用的是自签名证书, 又没有在用户电脑安装证书, 需要在浏览器添加如下配置:</p>
<p>&nbsp;--ignore-certificate-errors</p>
<p><img src="https://img2024.cnblogs.com/blog/3207251/202406/3207251-20240614111252538-44377371.png"></p>
<p>&nbsp;</p>
</div><br><br>
来源:https://www.cnblogs.com/shuyuanutil/p/18247466
頁: [1]
查看完整版本: Angular 集成 StreamSaver 大文件下载