如何通过SpringBoot服务在Angular中播放Amazon S3存储的MP4视频?
Hey there! Let's break down how to solve both of your video-related needs with Angular and Spring Boot connected to Amazon S3.
1. Render MP4 from S3 in Angular 4
First, let's make sure your Spring Boot backend is correctly serving the MP4 file from S3, then hook it up to your Angular 4 app.
Backend (Spring Boot)
Here's the completed and extended version of your getFile endpoint to properly handle video delivery:
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.model.S3Object; import com.amazonaws.services.s3.model.S3ObjectInputStream; import jakarta.servlet.http.HttpServletRequest; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @RestController public class S3VideoController { private final AmazonS3 amazonS3; private final String bucket = "your-bucket-name"; // Replace with your actual bucket name private final String videoKey = "fileIcon"; // Your video file's key in S3 // Constructor injection for AmazonS3 (assumes you've configured S3 client in your app) public S3VideoController(AmazonS3 amazonS3) { this.amazonS3 = amazonS3; } @RequestMapping(value = "/getFile") public ResponseEntity<StreamingResponseBody> getObject(HttpServletRequest request) throws IOException { S3Object s3Object = amazonS3.getObject(bucket, videoKey); S3ObjectInputStream inputStream = s3Object.getObjectContent(); long contentLength = s3Object.getObjectMetadata().getContentLength(); String contentType = s3Object.getObjectMetadata().getContentType(); // Set headers to enable proper video handling in browsers HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.parseMediaType(contentType != null ? contentType : "video/mp4")); headers.setContentLength(contentLength); headers.set("Accept-Ranges", "bytes"); // Handle range requests (critical for streaming/skipping in videos) String rangeHeader = request.getHeader("Range"); if (rangeHeader != null) { // Simplified range parsing (extend for full production robustness) String[] rangeParts = rangeHeader.replace("bytes=", "").split("-"); long start = Long.parseLong(rangeParts[0]); long end = rangeParts.length > 1 ? Long.parseLong(rangeParts[1]) : contentLength - 1; long chunkLength = end - start + 1; headers.set("Content-Range", "bytes " + start + "-" + end + "/" + contentLength); inputStream.skip(start); // Jump to the requested start position StreamingResponseBody responseBody = outputStream -> { copyStreamRange(inputStream, outputStream, chunkLength); }; return new ResponseEntity<>(responseBody, headers, HttpStatus.PARTIAL_CONTENT); } // Return full file if no range header is present StreamingResponseBody responseBody = outputStream -> { copyFullStream(inputStream, outputStream); }; return new ResponseEntity<>(responseBody, headers, HttpStatus.OK); } // Helper to copy entire input stream to output private void copyFullStream(InputStream input, OutputStream output) throws IOException { byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = input.read(buffer)) != -1) { output.write(buffer, 0, bytesRead); } input.close(); } // Helper to copy a specific range of the stream private void copyStreamRange(InputStream input, OutputStream output, long remaining) throws IOException { byte[] buffer = new byte[4096]; int bytesRead; while (remaining > 0 && (bytesRead = input.read(buffer, 0, (int) Math.min(buffer.length, remaining))) != -1) { output.write(buffer, 0, bytesRead); remaining -= bytesRead; } input.close(); } }
Frontend (Angular 4)
Use the native HTML5 <video> tag in your component template to render the video:
<video controls width="640" height="360" class="video-player"> <source [src]="videoUrl" type="video/mp4"> Your browser does not support HTML5 video playback. </video>
In your Angular component class:
import { Component } from '@angular/core'; @Component({ selector: 'app-s3-video-player', templateUrl: './s3-video-player.component.html' }) export class S3VideoPlayerComponent { videoUrl = '/api/getFile'; // Match your Spring Boot endpoint path }
Don't forget to configure CORS in Spring Boot to allow requests from your Angular domain—add a @CrossOrigin annotation to your controller or set up global CORS config.
2. Angular 5 Video Streaming Demo (InputStream from S3)
The core logic for streaming is identical to the Angular 4 solution, since streaming relies on browser capabilities and proper backend headers. Here's how to set it up for Angular 5:
Angular 5 Component Example
Template (works seamlessly for streaming):
<div class="streaming-video-container"> <video controls autoplay muted width="720" height="405"> <source [src]="streamingVideoUrl" type="video/mp4"> Your browser doesn't support HTML5 video streaming. </video> </div>
Component class:
import { Component } from '@angular/core'; @Component({ selector: 'app-streaming-video-player', templateUrl: './streaming-video-player.component.html', styleUrls: ['./streaming-video-player.component.css'] }) export class StreamingVideoPlayerComponent { streamingVideoUrl = '/api/getFile'; // Same backend endpoint as before }
Key Streaming Notes
- The backend code above supports range requests (returning
206 Partial Content), which lets users skip ahead in the video without downloading the entire file—this is true streaming. - Ensure your S3 object has the correct
Content-Typeset tovideo/mp4(update via AWS Console or S3 API if needed).
Quick Troubleshooting
- CORS Errors: Double-check your Spring Boot CORS configuration if you see browser console errors about cross-origin requests.
- Video Not Loading: Verify your S3 bucket policy allows access to the file, and that the
videoKeymatches your S3 object's key. - Streaming Glitches: Confirm the backend returns the
Accept-Ranges: bytesheader and handles range requests (the code above includes this).
内容的提问来源于stack exchange,提问作者sujeet kumar

