如何将VideoView的请求从GET方法改为POST方法
Android VideoView 发送POST请求缓冲视频的解决方案
VideoView的setVideoURI(uri, headers)方法仅支持添加请求头,无法修改默认的GET请求方法——这是因为底层依赖的MediaPlayer固定使用GET请求加载视频资源。要实现POST请求加载视频,需要通过自定义数据源的方式来处理,以下是两种可行方案:
方案一:使用ExoPlayer(推荐)
ExoPlayer是Google官方推荐的替代VideoView的媒体播放库,具备更强的定制性,可轻松实现POST请求逻辑:
- 添加依赖
在Module级别的build.gradle中加入ExoPlayer依赖(版本可根据需求调整):
implementation "com.google.android.exoplayer:exoplayer-core:2.19.1" implementation "com.google.android.exoplayer:exoplayer-ui:2.19.1"
- 替换布局组件
将布局中的VideoView替换为ExoPlayer的PlayerView:
<com.google.android.exoplayer2.ui.PlayerView android:id="@+id/player_view" android:layout_width="match_parent" android:layout_height="match_parent"/>
- 自定义POST请求数据源
创建自定义HttpDataSource.Factory,强制设置请求方法为POST并添加自定义头:
private HttpDataSource.Factory createPostHttpDataSourceFactory() { return new DefaultHttpDataSource.Factory() { @Override public HttpDataSource createDataSource() { DefaultHttpDataSource dataSource = super.createDataSource(); // 设置请求方法为POST dataSource.setRequestMethod("POST"); // 添加自定义请求头 dataSource.setRequestProperty("Cookie", "CloudFront-Policy=xx; Domain=xx; Path=xx"); dataSource.setRequestProperty("User-Agent", "My Agent"); // 若需发送POST请求体,可在此扩展逻辑 return dataSource; } }; }
- 初始化播放器并加载视频
PlayerView playerView = findViewById(R.id.player_view); SimpleExoPlayer player = new SimpleExoPlayer.Builder(this).build(); playerView.setPlayer(player); // 构建媒体项 MediaItem mediaItem = MediaItem.fromUri("http://192.168.0.173/1.mp4"); // 关联自定义数据源工厂并准备播放 player.setMediaSource(new ProgressiveMediaSource.Factory(createPostHttpDataSourceFactory()) .createMediaSource(mediaItem)); player.prepare(); player.play();
方案二:自定义MediaDataSource配合VideoView
若必须使用VideoView,可通过自定义MediaDataSource实现POST请求,再关联到VideoView:
- 实现自定义MediaDataSource
public class PostMediaDataSource extends MediaDataSource { private HttpURLConnection connection; private InputStream inputStream; private final String url; private final Map<String, String> headers; public PostMediaDataSource(String url, Map<String, String> headers) { this.url = url; this.headers = headers; } @Override public long getSize() throws IOException { openConnection(); return connection.getContentLength(); } @Override public int readAt(long position, byte[] buffer, int offset, int size) throws IOException { if (inputStream == null) { openConnection(); // 支持范围请求,适配VideoView的分段缓冲逻辑 if (position > 0) { connection.setRequestProperty("Range", "bytes=" + position + "-"); connection.connect(); inputStream = connection.getInputStream(); } } return inputStream.read(buffer, offset, size); } private void openConnection() throws IOException { if (connection != null) return; URL urlObj = new URL(url); connection = (HttpURLConnection) urlObj.openConnection(); connection.setRequestMethod("POST"); // 写入自定义请求头 for (Map.Entry<String, String> entry : headers.entrySet()) { connection.setRequestProperty(entry.getKey(), entry.getValue()); } // 若需发送POST请求体,打开输出流并写入数据 // connection.setDoOutput(true); // OutputStream os = connection.getOutputStream(); // os.write("request_body_content".getBytes()); // os.flush(); connection.connect(); inputStream = connection.getInputStream(); } @Override public void close() throws IOException { if (inputStream != null) inputStream.close(); if (connection != null) connection.disconnect(); } }
- 关联到VideoView
VideoView videoplayer = findViewById(R.id.videoplayer); Map<String, String> headers = new HashMap<>(); headers.put("Cookie","CloudFront-Policy=xx; Domain=xx; Path=xx"); headers.put("User-Agent","My Agent"); String videoUrl = "http://192.168.0.173/1.mp4"; MediaPlayer mediaPlayer = new MediaPlayer(); try { mediaPlayer.setDataSource(new PostMediaDataSource(videoUrl, headers)); mediaPlayer.prepareAsync(); mediaPlayer.setOnPreparedListener(mp -> { videoplayer.setMediaPlayer(mediaPlayer); videoplayer.start(); }); } catch (IOException e) { e.printStackTrace(); }
注意事项
- 若服务器要求POST请求携带请求体,需在对应代码中添加写入请求体的逻辑
- 方案二中必须支持
Range请求,否则VideoView的分段缓冲逻辑会失效,导致播放异常 - ExoPlayer方案具备更好的兼容性和扩展性,推荐优先使用
内容的提问来源于stack exchange,提问作者Ghost Ghaith
相关产品推荐
相关产品推荐

