- Case study of video manual service based on ReactPlayer -
1. Project overview
This case is a project conducted to convert the existing PDF-based user manual system into a video content-based service. In the existing system, when users click the manual button, the frontend directly accesses AWS S3 to download the PDF file. While this method was simple to implement, it had limitations as users found it difficult to check the manual and the actual work screen simultaneously, and it was challenging to convey complex procedures intuitively.
The client requested a PIP (Picture in Picture) feature that allows users to view manual videos while maintaining the work screen. At the same time, due to security policies, direct access to AWS S3 had to be restricted, and there were also constraints that sensitive authentication information could not be included in the URL parameters. Therefore, the core of this project was not merely implementing a simple video playback function, but designing an authentication and streaming structure that satisfies both browser-based video playback architecture and security requirements.
2. Technology Selection and Design Direction
In the frontend area, we introduced ReactPlayer, a React-based video player library. ReactPlayer operates based on the HTML5 video tag and has high compatibility with the React environment, as well as the advantages of relatively simple PIP functionality and playback state control.
However, ReactPlayer uses the request method of the video tag internally, so the video file request is performed using the GET method by default. Since it is difficult to include authentication information in the request body or freely configure headers like a typical API call, it was necessary to design a separation between the authentication process and the actual video playback request.
Sample code 1. Example of calling ReactPlayer
|
|
The above example illustrates the structure in which ReactPlayer plays a video based on the video playback endpoint received from the server. The authentication information is not included in the URL and is handled by passing a temporary token issued during the pre-authentication phase via a Cookie.
3. Architecture Redesign
The existing structure allowed the Frontend to directly access AWS S3. However, maintaining the same structure when providing video content could lead to exposure of storage paths, URL reuse, and potential bypass of access controls. Therefore, we have separated the server roles as follows.
|
Frontend |
Server A is responsible for user authentication, authorization validation, temporary token issuance, and streaming request relay. Server B has been separated to only handle actual video file retrieval and AWS S3 access. This is to prevent the client from knowing the storage path directly and to ensure that all video requests pass the server's authentication validation.
4. Authentication and Playback Flow
When the user clicks the manual button, it does not immediately call the video player, but first requests the user validation API from Server A. Once the validation is complete, Server A issues an endpoint for video playback and a time-limited temporary token. The temporary token is stored in the browser cookie and is sent along with the video endpoint request when ReactPlayer calls it.
Sample Code 2. Video Playback Information Request
|
const openManualVideo = async (manualId: string) => { |
This code is an example of requesting the video playback endpoint when the manual button is clicked. At this stage, the server responds by validating the user's permissions and storing a temporary token in the Cookie.
Sample Code 3. Example of Issuing Temporary Token Cookie
|
ResponseCookie cookie = ResponseCookie.from("VIDEO_ACCESS_TOKEN", token) |
The Cookie has been configured with HttpOnly, Secure, and SameSite options to limit script access and unnecessary external transmission. Additionally, it has been designed to be used restrictively only for video requests by specifying the path and maxAge.
5. Streaming Broadcast Processing
Video streaming continuously delivers large amounts of data, unlike regular file downloads, and partial requests based on the Range Header may occur when users move the playback position. Thus, Server A must pass the client's Range Header to Server B and relay Server B's response status and key headers back to the client.
Sample Code 4. Streaming Proxy Based on Range Header
|
@GetMapping("/api/videos/{manualId}/stream") |
The key of this method is that it does not load the entire file into memory, such as bodyToMono(Resource.class) or bodyToMono(byte[].class). By using bodyToFlux(DataBuffer.class), video data can be delivered in chunks, making it suitable for large-scale video processing.
Sample Code 5. Key Streaming Header Filtering
|
private boolean isStreamingHeader(String name) { |
Headers such as Content-Range, Accept-Ranges, and Content-Length are necessary for the browser to determine the length of the video and the range of partial responses. It is especially important to preserve these headers for navigation and stable playback.
6. Results and Effects
As a result of the implementation, users were able to instantly play videos in the browser and utilize both the actual work screen and video manual simultaneously through the PIP function. Additionally, by removing direct access to AWS S3 and applying server-based access control, we were able to meet security requirements.
• Remove direct exposure of AWS S3
• Remove transmission of sensitive information based on URL
• Allow access to video endpoint after user validation
• Restricted access control based on temporary tokens
• Support for video playback and navigation based on Range Header
7. Conclusion
Through this case, I experienced a design case that not only involved adding a video player but also considered the operation of ReactPlayer and the HTML5 video tag, the customer's security policy, the separation of roles between servers, and the streaming processing method comprehensively. By separating the authentication and playback processes and clearly dividing the responsibilities of Server A and Server B, I was able to secure both user experience and security.
In particular, I felt that in a practical environment, understanding the constraints of security policies and browser operation methods is more important than the implementation of functionalities themselves. This project confirmed that, in video-based manual services, it is essential to consider authentication structure, data flow, streaming header processing, and operational security policies for reliable service provision.
NZ