feat: 支持gzip传输

This commit is contained in:
wushuo
2025-12-15 09:43:42 +08:00
parent 2b47ec8a7d
commit 95f63b445a
4 changed files with 118 additions and 25 deletions

View File

@@ -8,6 +8,7 @@ import cn.hutool.core.io.FileUtil;
import cn.hutool.core.text.StrFormatter;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.http.Header;
import cn.hutool.http.server.HttpServerRequest;
import cn.hutool.http.server.HttpServerResponse;
import lombok.Cleanup;
@@ -33,7 +34,7 @@ public class DownloadLogsAction implements BaseAction {
String contentType = getContentType(filename);
response.setContentType(contentType);
response.setHeader("Content-Disposition", StrFormatter.format("inline; filename=\"{}\"", filename));
response.setHeader(Header.CONTENT_DISPOSITION, StrFormatter.format("inline; filename=\"{}\"", filename));
@Cleanup
OutputStream outputStream = response.getOut();

View File

@@ -21,6 +21,7 @@
"vue": "^3.5.25"
},
"devDependencies": {
"vite-plugin-compression": "^0.5.1",
"@vitejs/plugin-vue": "^6.0.3",
"shiki": "^3.20.0",
"terser": "^5.44.1",

View File

@@ -4,6 +4,7 @@ import path from 'path'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import {ElementPlusResolver} from 'unplugin-vue-components/resolvers'
import compression from 'vite-plugin-compression'
let serverHost = process.env['SERVER_HOST'];
@@ -28,7 +29,19 @@ export default defineConfig({
resolvers: [ElementPlusResolver({
importStyle: 'css',
})]
})
}),
compression({
// 输出压缩日志
verbose: true,
// 是否禁用压缩
disable: false,
// 对超过10KB的文件进行压缩
threshold: 10240,
// 使用gzip压缩
algorithm: 'gzip',
// 压缩后文件的扩展名
ext: '.gz'
}),
],
resolve: {
alias: {

View File

@@ -2,6 +2,7 @@ package ani.rss.web.action;
import ani.rss.commons.MavenUtils;
import ani.rss.web.annotation.Auth;
import ani.rss.web.util.ServerUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.EnumerationIter;
import cn.hutool.core.io.FileUtil;
@@ -12,15 +13,20 @@ import cn.hutool.http.Header;
import cn.hutool.http.server.HttpServerRequest;
import cn.hutool.http.server.HttpServerResponse;
import lombok.Cleanup;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
@@ -73,11 +79,18 @@ public class RootAction implements BaseAction {
try {
EnumerationIter<URL> resourceIter = ResourceUtil.getResourceIter(fileName);
for (URL url : resourceIter) {
@Cleanup
InputStream inputStream = toInputStream(url, fileName);
if (Objects.isNull(inputStream)) {
Optional<FileInfo> fileInfoOptional = toFileInfo(url, fileName);
if (fileInfoOptional.isEmpty()) {
continue;
}
FileInfo fileInfo = fileInfoOptional.get();
Boolean gzip = fileInfo.getGzip();
if (gzip) {
response.setHeader(Header.CONTENT_ENCODING, "gzip");
}
@Cleanup
InputStream inputStream = fileInfo.getInputStream();
String contentType = getContentType(fileName);
if (List.of("text/css", "application/x-javascript").contains(contentType)) {
response.setHeader(Header.CACHE_CONTROL, "private, max-age=86400");
@@ -99,29 +112,94 @@ public class RootAction implements BaseAction {
return false;
}
public InputStream toInputStream(URL url, String fileName) throws IOException {
String protocol = url.getProtocol();
public InputStream toStream(AtomicBoolean gzip, String fileName) {
JarFile jarFile = MavenUtils.JAR_FILE;
if (Objects.isNull(jarFile)) {
return null;
}
InputStream inputStream = null;
if (protocol.equals("file")) {
File file = new File(URLUtil.decode(url.getFile(), StandardCharsets.UTF_8));
if (!file.isDirectory()) {
inputStream = FileUtil.getInputStream(file);
}
} else {
JarFile jarFile = MavenUtils.JAR_FILE;
if (Objects.isNull(jarFile)) {
return null;
}
JarEntry jarEntry = jarFile.getJarEntry(fileName);
if (Objects.isNull(jarEntry)) {
return null;
}
if (!jarEntry.isDirectory()) {
inputStream = jarFile.getInputStream(jarEntry);
if (gzip.get()) {
String gzipFileName = fileName + ".gz";
JarEntry jarEntry = jarFile.getJarEntry(gzipFileName);
if (Objects.nonNull(jarEntry) && !jarEntry.isDirectory()) {
try {
return jarFile.getInputStream(jarEntry);
} catch (IOException ignored) {
}
}
}
return inputStream;
gzip.set(false);
JarEntry jarEntry = jarFile.getJarEntry(fileName);
if (Objects.isNull(jarEntry)) {
return null;
}
if (!jarEntry.isDirectory()) {
try {
return jarFile.getInputStream(jarEntry);
} catch (IOException ignored) {
}
}
return null;
}
public InputStream toStream(AtomicBoolean gzip, URL url) {
String filepath = URLUtil.decode(url.getFile(), StandardCharsets.UTF_8);
String gzipFilepath = filepath + ".gz";
if (gzip.get()) {
File file = new File(gzipFilepath);
if (file.exists() && file.isFile()) {
try {
return FileUtil.getInputStream(file);
} catch (Exception ignored) {
}
}
}
gzip.set(false);
File file = new File(filepath);
if (file.exists() && file.isFile()) {
try {
return FileUtil.getInputStream(file);
} catch (Exception ignored) {
}
}
return null;
}
public Optional<FileInfo> toFileInfo(URL url, String fileName) {
HttpServerRequest request = ServerUtil.REQUEST.get();
String acceptEncoding = request.getHeader(Header.ACCEPT_ENCODING);
AtomicBoolean gzip = new AtomicBoolean(StrUtil.contains(acceptEncoding, "gzip"));
String protocol = url.getProtocol();
InputStream inputStream;
if (protocol.equals("file")) {
inputStream = toStream(gzip, url);
} else {
inputStream = toStream(gzip, fileName);
}
if (Objects.isNull(inputStream)) {
return Optional.empty();
}
FileInfo fileInfo = new FileInfo();
fileInfo.setInputStream(inputStream)
.setFileName(fileName)
.setGzip(gzip.get());
return Optional.of(fileInfo);
}
@Data
@Accessors(chain = true)
public static class FileInfo implements Serializable {
private String fileName;
private InputStream inputStream;
private Boolean gzip;
}
}