Docker部署项目
Docker-容器化部署前端项目
前端项目打包后,通过构建镜像,创建容器部署。
基本实现
Dockerfile
FROM nginx
COPY dist /usr/share/nginx/html/
# Copy a configuration file from the current directory
COPY nginx.conf /etc/nginx/
# RUN service nginx start
# Expose ports
# EXPOSE 80
# ENTRYPOINT ["bash", "/usr/share/nginx/html/changeIP.sh"]
nginx.conf
worker_processes 1;
events { worker_connections 1024; }
http {
include mime.types;
sendfile on;
server {
root /usr/share/nginx/html/;
index index.html;
server_name localhost;
listen 80;
location /nginx_status {
stub_status on;
# allow 127.0.0.1; #only allow requests from localhost
# deny all; #deny all other hosts
}
}
}
docker-compose.yml
version: '3'
services:
image_name:
container_name: c_name
build:
context: .
dockerfile: Dockerfile
ports:
- '5173:5173'
命令
docker compose
docker-compose up -d --build
docker 打包镜像
docker build -t image_name:tag . ->docker build -t my-app:v1 .
docker 镜像压缩包
docker save -o xxx.tar image_name:tag
文件下载
文件分片下载
实现一个文件分片下载案例。
工作中对于下载的方式有很多,可以利用FileSaver插件来实现统一的下载方式,减少多次编写a标签进行下载。
文件下载方式
文件下载常用的方式,列举了直接使用a标签的方式和使用插件的方式。
a标签
设置a标签的dowload属性
调用createObjectURL方法创建blob的下载链接
执行a标签的click事件
最后调用revokeObjectURL移出内部映射,释放内存
const a = document.createElement("a");
a.download = filename;
a.href = URL.createObjectURL(blob);
a.click();
URL.revokeObjectURL(a.href)
FileSaver.js
FileSaver.js是客户端解决保存文件的一个解决方案,在项目中引入该JS库,利用统一方式进行文件保存。
import { saveAs } from 'file-saver';
FileSaver saveAs(
Blob/File/Url,
optional DOMString filename,
optional Object { autoBom }
)
方案1
保存文件时,如果浏览器环境支持a标签的download属性,且非macos webview环境下,会优先使用a.download来进行文件保存。
字符串类型
FileSaver源码内部多了一层CORS机制的判断。
saveAs('http://xxx.xxx...')
function saveAs(blob, name, opts) {
var URL = _global.URL || _global.webkitURL;
var a = document.createElement("a");
name = name || blob.name || "download";
a.download = name;
a.rel = "noopener";
if (typeof blob === "string") {
a.href = blob;
if (a.origin !== location.origin) { // (1)
corsEnabled(a.href)
? download(blob, name, opts)
: click(a, (a.target = "_blank"))
} else { // (2)
click(a);
}
} else {
...
}
}
CORS判断
通过corsEnabled
方法来判断是否支持CORS
机制。
corsEnabled
方法通过XMLHttpRequest API 来发起 HEAD
请求,判断请求返回的状态码区间是否在[200-299]
download
方法和click方法都是FileSaver内部方法。
download
download
方法通过 XMLHttpRequest API 来发起 HTTP
请求,响应类型为 blob
,然后调用自身saveAs
方法来进行资源下载。
click
click
方法通过node对象来派发点击事件,来实现不支持 CORS
机制或同域的情形
blob类型
blob
类型主要是通过createObjectURL
方法来创建资源对象链接,实现资源下载。
saveAs(blob)
function saveAs(blob, name, opts) {
var URL = _global.URL || _global.webkitURL
var a = document.createElement("a")
name = name || blob.name || "download"
a.download = name;
a.rel = "noopener";
if (typeof blob === "string") {
// 省略处理字符串类型参数
} else {
a.href = URL.createObjectURL(blob);
setTimeout(function () {
URL.revokeObjectURL(a.href);
}, 4e4); // 40s
setTimeout(function () {
click(a)
}, 0);
}
}
方案2
IE10 浏览器中,msSaveBlob
和msSaveOrOpenBlob
方法允许用户在客户端上保存文件
blob类型
在满足 “msSaveOrOpenBlob” in navigator 条件时, FileSaver.js
会使用方案2来实现文件保存
function saveAs(blob, name, opts) {
name = name || blob.name || "download";
if (typeof blob === "string") {
...
} else {
navigator.msSaveOrOpenBlob(bom(blob, opts), name)
}
}
方案3
方案1和方案2都不支持的话,FileSaver.js 就会使用 FileReader API 和 open API 新开窗口来实现文件保存。
blob类型
在其他方案都无法使用的情况下,FileSaver 会使用 FileReader API 先把 Blob 对象转换为 Data URL,然后再把该 Data URL 地址赋值给新开的窗口或当前窗口的 location 对象
使用FileSaver插件,可以应对多种环境的文件下载。
文件分片下载
HTTP头部添加Range,通知服务器返回范围内的文件。
代码实现
获取文件大小
通过HEAD
请求来获取content-length
/**
* 获取文件大小
*/
const getContentLength = async url => {
const res = await request({
url,
method: 'HEAD'
})
return res.headers['content-length']
}
下载并发控制
插件 asyncPool
/**
* 并发控制
*/
const ReqAsyncPool = async (...args) => {
const allArray = []
for await (const ms of asyncPool(...args)) {
allArray.push(ms)
}
return allArray
}
指定请求范围
指定请求文件的范围 range
,响应为 arraybuffer
/**
* 文件范围控制
*/
const getBinaryContent = async (url, start, end) => {
const res = await request({
url,
method: 'GET',
headers: {
Range: `bytes=${start}-${end}`
},
responseType: 'arraybuffer'
})
return { buffer: res.data }
}
文件合并
将arraybuffer
转换为 Unit8Array
,进行合并操作
/**
* 文件合并
*/
const concatenate = (arrays) => {
if (!arrays.length) return null;
let totalLength = arrays.reduce((acc, value) => acc + value.length, 0);
let result = new Uint8Array(totalLength);
let length = 0;
for (let array of arrays) {
result.set(array, length);
length += array.length;
}
return result;
}
文件保存
FileSaver
可以快速进行Blob
类型的存储。
/**
* 文件保存
*/
const fileSave = ({ name, sortedBuffers, mime = "application/octet-stream" }) => {
const blob = new Blob([sortedBuffers], { type: mime });
// 使用 saveAs
saveAs(blob, name)
}
下载事件
/**
* 下载
*/
const downloadFile = async () => {
const url = 'http://xxx.xxx'
// 1. 文件大小
const contentLength = await getContentLength(url)
// 2. 文件分片数量
const chunks =
typeof chunkSize === 'number' ? Math.ceil(contentLength / chunkSize) : 1
// 3. 并发请求
const res = await ReqAsyncPool(
3,
[...new Array(chunks).keys()],
i => {
let start = i * chunkSize
let end = i + 1 == chunks ? contentLength - 1 : (i + 1) * chunkSize - 1
return getBinaryContent(start, end, i)
}
)
// 4. arraybuffer -> Unit8Array
const sortedBuffers = res
.map((item) => new Uint8Array(item.buffer));
// 5. 合并
const concatenateData = concatenate(sortedBuffers)
fileSave({name: 'qjtp.jpg', sortedBuffers: concatenateData, mime: "image/jpeg" })
}
模拟下载
使用Koa
的koa-range
中间件。
文件分片下载流
在文件下载时,保存的分片都在内存,在最后读取内存中的分片,进行文件合并,如果下载的文件非常大,直接生成的Blob
很大,那么浏览器内存是不够用来分片缓存的,需要更换分片保存的方法。
FileSaver.js的仓库文档
If you need to save really large files bigger than the blob’s size limitation or don’t have enough RAM, then have a look at the more advanced StreamSaver.js that can save data directly to the hard drive asynchronously with the power of the new streams API
如果有超大文件,可以使用StreamSaver来保存大文件。