经常做pdf预览的小伙伴都知道,如 pdfjs,pdfjs-dist,react-pdf等等,各种库,但是其实就是为了预览一下pdf内容。
而且pdfjs-dist还会依赖node-pre-gyp,做前端的都知道,这个gpy是有多恶心。
好了,为了不用任何库,就可以预览pdf,你可以如下操作:
1. 新窗口打开或将pdf地址放在iframe 的src里预览
写法如下:
<iframe src="https://example.com/test.pdf"></iframe>
这么做有一个问题,如果pdf的地址请求头是application/octet-stream的话,pdf会被下载下来,无法预览。
2. 使用ajax获取pdf之后,在iframe里预览。
import { useEffect, useState } from 'react';
const App = () => {
const [errorMsg, setErrorMsg] = useState('')
const [pdfBlobUrl, setPdfBlobUrl] = useState('')
const [loading, setLoading] = useState(false)
const [progress, setProgress] = useState(0)
const fetchPdfWithXHR = () => {
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://example.com/test.pdf', true); // 替换为实际的接口地址
// 设置请求头(根据需要)
xhr.setRequestHeader('Content-Type', 'application/json');
// 指定返回类型为 Blob
xhr.responseType = 'blob';
// 请求成功处理
xhr.onload = () => {
// 由于带进度下载的请求,status是206,不是200,所这里做一下处理。
if (xhr.status>=200 && xhr.status<300) {
// 将 Blob 数据生成 URL
const blob = new Blob([xhr.response], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
setPdfBlobUrl(url);
} else {
setErrorMsg('Failed to fetch PDF:' + xhr.status + xhr.statusText);
}
};
// 下载进度监听器
xhr.onprogress = (event) => {
if (event.lengthComputable) {
const v = loaded / total * 100
setProgress(Math.floor(v))
}
}
// 错误处理
xhr.onerror = () => {
console.error('Network error while fetching PDF.');
};
// 发送请求
const requestBody = JSON.stringify({
// 替换为实际的请求参数
token: '',
});
xhr.send(requestBody);
};
useEffect(() => {
fetchPdfWithXHR();
}, []);
return loading ? <div>Loading PDF {progress}%...</div> : pdfBlobUrl ? (
<iframe
src={pdfBlobUrl}
width="100%"
height="750px"
style={{ border: 'none' }}
/>
) : (
<p>{errorMsg}</p>
);
};
export default App;
这样做,无论是什么样的pdf,都可以实现预览了。当然,如果有跨域问题的请求,是不能用ajax的
如果既是跨域,又是application/octet-stream,这种情况,直接跳转新页面下载吧。用其他任何库,都无法解决的。
另外附上对应的java代码:
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.File;
import java.io.RandomAccessFile;
import java.io.OutputStream;
@RestController
public class FileDownloadController {
@GetMapping("/download")
public ResponseEntity<Void> downloadFile(
@RequestParam String filePath,
@RequestHeader(value = "Range", required = false) String rangeHeader,
HttpServletResponse response) throws Exception {
File file = new File(filePath);
if (!file.exists()) {
return ResponseEntity.notFound().build();
}
long fileLength = file.length();
long start = 0;
long end = fileLength - 1;
if (rangeHeader != null && rangeHeader.startsWith("bytes=")) {
String[] ranges = rangeHeader.substring(6).split("-");
start = Long.parseLong(ranges[0]);
if (ranges.length > 1 && !ranges[1].isEmpty()) {
end = Long.parseLong(ranges[1]);
}
}
long contentLength = end - start + 1;
response.setContentType("application/pdf");
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + file.getName());
response.setHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(contentLength));
response.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes");
response.setStatus(HttpStatus.PARTIAL_CONTENT.value());
try (RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
OutputStream out = response.getOutputStream()) {
byte[] buffer = new byte[8192];
randomAccessFile.seek(start);
long remaining = contentLength;
while (remaining > 0) {
int bytesRead = randomAccessFile.read(buffer, 0, (int) Math.min(buffer.length, remaining));
if (bytesRead == -1) {
break;
}
out.write(buffer, 0, bytesRead);
remaining -= bytesRead;
}
}
return ResponseEntity.ok().build();
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。