所以我想创建一个 Angular 的 Web 应用程序,除其他外,它还可以向用户显示 pdf 文件。 pdf 文件存储在数据库中,由 Spring Boot 后端检索并发送给用户。在本地计算机上运行时,一切正常。然而,当我想在基于 ngnix 的 docker 镜像中运行它时,问题就出现了。错误日志一直显示 MIME 类型存在问题。注意:这是专门针对 PDF 中的部分加载的,其他一切似乎都运行良好。
错误日志:
main-7X4J5JFT.js:50 Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "application/octet-stream". Strict MIME type checking is enforced for module scripts per HTML spec.
现在,我在整整 3 天的时间里尝试了很多 - 我的意思是很多 - 不同的解决方案。我可能会错过一些非常重要的东西,但我真的不知道我应该对我的项目进行哪些更改。作为参考,这里是 nginx.conf:
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri /index.html;
}
location ~* \.(?:ico|css|js|gif|jpe?g|png|woff2?|eot|ttf|svg|otf|webmanifest|txt|xml)$ {
expires 6M;
access_log off;
add_header Cache-Control "public";
}
location ~* \.pdf$ {
add_header Content-Type application/pdf;
expires 1M;
access_log off;
add_header Cache-Control "public";
}
location ~ \.css {
add_header Content-Type text/css;
}
location ~ \.js {
add_header Content-Type application/x-javascript;
}
}
这是我的dockerfile:
# Step 1: Use a Node.js base image to build the app
FROM node:22.13.0-alpine AS build
# Set the working directory
WORKDIR /app
# Copy package.json and package-lock.json
COPY package.json package-lock.json ./
# install project dependencies
RUN npm install
RUN npx ngcc --properties es2025 browser module main --first-only --create-ivy-entry-points
# Copy the entire project to the container
COPY . .
# Build the Angular app
RUN npm run build
# Step 2: Use an NGINX base image to serve the app
FROM nginx:stable
# Copy built Angular app from the build stage to the NGINX HTML folder
COPY --from=build /app/dist/cyberlab-frontend/browser /usr/share/nginx/html
RUN chmod -R 755 /usr/share/nginx/html
# Copy custom Nginx configuration file
COPY nginx.conf /etc/nginx/conf.d/default.conf
# Expose the default NGINX port
EXPOSE 80
这是后端处理 pdf 文件发送的部分:
@RateLimiter(name = "default")
@GetMapping("/fetchLab")
public ResponseEntity<byte[]> getLab(@RequestParam long labId, @RequestParam String labName) {
try {
Optional<LabDTO> labDetails = this.labService.getLabById(labId);
if (labDetails.isEmpty()) {
throw new Exception("Could not find specified lab");
}
if (!labDetails.get().name().equals(labName)){
throw new Exception("LabId and Labname do not match");
}
byte[] pdf = labDetails.get().pdf();
String fileName = labDetails.get().name() + ".pdf";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_PDF);
headers.setContentDisposition(ContentDisposition.inline().filename(fileName).build());
return new ResponseEntity<>(pdf, headers, HttpStatus.OK);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.body(String.format("{\"success\":false,\"message\":\"%s\"}", e.getMessage()).getBytes());
}
}
最后,应该处理 pdf 文件查看器的前端方法。请注意,在我的 HTML 中,我使用的是 ngx-extended-pdf-viewer:
ngOnInit(): void {
this.labId = this.route.snapshot.params['labId'];
this.labName = this.route.snapshot.params['labName'];
this.labService.fetchLab(this.labId!, this.labName!).subscribe({
next: (file: Blob) => {
console.log('Received Blob Size:', file.size); // Log Blob size
if (file.size > 0) {
this.pdfFile = URL.createObjectURL(file); // Pass this URL to your PDF viewer
} else {
window.alert('Received an empty PDF file');
}
},
error: (err) => {
console.error('Failed to fetch the lab:', err);
window.alert('Page does not exist or an error occurred.');
}
});
}
您需要少考虑最终目标,多考虑错误消息告诉您的内容。
主-7X4J5JFT.js:50
因此错误发生在文件 main-7X4J5JFT.js 的第 50 行。
查看该文件的第 50 行,看看它在做什么
无法加载模块脚本:需要 JavaScript 模块脚本,但服务器以 MIME 类型“application/octet-stream”进行响应。
因此它尝试加载 JavaScript 模块,服务器响应了一些内容,其中包含
Content-Type: application/octet-stream
查看浏览器开发人员工具的“网络”选项卡。找到该文件的请求。 它将是具有该内容类型的请求。它的文件名可能位于 main-7X4J5JFT.js.
的第 50 行请注意,这与 PDF 无关。这都是关于加载您的(可能是)第三方库。
鉴于我无法访问您通过调试获得的信息,这个答案的其余部分是一个明智的猜测。