基于Spring MVC实现外部HLS流的后端Basic Auth代理播放
我在开发一个基于Spring MVC的Java Web应用时,需要代理访问外部HLS服务器(rtsp-simple-server/mediamtx)——这个服务器仅启用HLS协议,流地址示例为https://mediaserver.url:port/stream1,且受HTTP Basic Auth保护。核心需求是后端完成认证,前端用hls.js播放视频时不弹出登录框、不暴露凭证。
之前踩的坑
一开始试过用WebFilter和RestTemplate处理:用RestTemplate能成功获取m3u8清单,但浏览器请求分片时会触发文件保存提示,根本没法正常播放。
最终可行方案:Controller代理请求
通过编写Spring Controller实现请求转发,让后端注入认证信息并流式转发HLS数据,完美解决了分片播放的问题。
1. 配置带认证的RestTemplate
给RestTemplate添加BasicAuthorizationInterceptor,一次性注入HLS服务器的账号密码,不用每次请求手动构造Auth头:
@Bean public RestTemplate hlsRestTemplate() { RestTemplate restTemplate = new RestTemplate(); String username = "your-username"; String password = "your-password"; restTemplate.getInterceptors().add(new BasicAuthorizationInterceptor(username, password)); return restTemplate; }
2. 编写代理Controller
用StreamingResponseBody流式转发外部服务器的响应,保证分片数据能被浏览器正常解析:
@Controller @RequestMapping("/streams") public class HlsStreamProxyController { private final RestTemplate hlsRestTemplate; private static final String HLS_SERVER_BASE_URL = "https://mediaserver.url:port"; public HlsStreamProxyController(RestTemplate hlsRestTemplate) { this.hlsRestTemplate = hlsRestTemplate; } @GetMapping("/{streamName}/**") public ResponseEntity<StreamingResponseBody> proxyStream(@PathVariable String streamName, HttpServletRequest request) { // 拼接外部HLS服务器的完整请求路径 String requestPath = request.getRequestURI().replace("/streams/" + streamName, ""); String externalUrl = HLS_SERVER_BASE_URL + "/" + streamName + requestPath; // 获取外部响应的头信息,原样返回给前端(确保Content-Type等正确) HttpHeaders headers = hlsRestTemplate.headForHeaders(externalUrl); // 流式转发响应体,避免内存占用过大 StreamingResponseBody responseBody = outputStream -> { ResponseEntity<Resource> response = hlsRestTemplate.getForEntity(externalUrl, Resource.class); try (InputStream inputStream = response.getBody().getInputStream()) { IOUtils.copy(inputStream, outputStream); } }; return ResponseEntity.ok() .headers(headers) .body(responseBody); } }
提示:需要导入
org.apache.commons.io.IOUtils(或用Java原生的InputStream.transferTo(outputStream)替代)处理流复制。
3. 前端播放方式
前端可以直接用hls.js加载代理后的流地址,或者用iframe嵌入:
<!-- 方式1:hls.js直接播放 --> <video id="videoPlayer" controls width="640" height="480"></video> <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script> <script> const video = document.getElementById('videoPlayer'); if (Hls.isSupported()) { const hls = new Hls(); hls.loadSource('./streams/camera1/index.m3u8'); hls.attachMedia(video); } </script> <!-- 方式2:iframe嵌入 --> <iframe src="./streams/camera1/" width="640" height="480" frameborder="0"></iframe>
这套方案里,后端自动完成与外部HLS服务器的认证,前端完全不用接触凭证,也不会弹出登录弹窗,分片数据能被hls.js正常解析播放。
内容的提问来源于stack exchange,提问作者Stefano Colla

