抖音开放平台-视频切片-视频分片上传-不合法的参数ID-不合法的对象ID

本文已参与「新人创作礼」活动,一起开启掘金创作之路

问题描述

1、最近遇到个问题,做业务需要管理几个抖音账号,用抖音开放平台做分片上传视频,多次返回不合法参数id,提交工单之后给的回复没有任何参考价值。 2、例如视频文件按15M进行切片,调用分片上传初始化接口,获取一个upload-id,执行上传;我只上传第一个视频观察返回信息。第一次第一个切片执行上传,返回不合法参数id,继续执行第二个切片的上传,还是不合法参数id,之后的切片就不用考虑了;第二次执行切片上传,重新获取upload-id,上传第一切片,发现居然上传成功了,紧接着尝试上传其他切片,都能成功;第三次执行上传,重新获取upload-id,上传第一个切片,发现又成了不合法参数id,后续的其他切片都上传失败。

工单信息

工单状态

已解决 工单说明 同样的上传参数,39M的视频分片上传,15M+24M切分,第一次上传失败,20210810XXXXXXXXXXXXXXX4927233640,不合法的对象id,但是我再操作一次就能上传成功了,2021081XXXXXXXXXXXXXXX452192B2343BD;紧接着进行第三次上传,又出现了问题202108XXXXXXXXXXXX12059196332065FA;请问相同的文件,为什么能有成功的情况?不合法的对象id到底指的是什么?

2021年08月10日 21:32

工单回复:

您好,单片建议大小在20M以内,太大会导致传输不稳定 在这里插入图片描述

这工单的回复完全没有什么参考意义,等这个工单的处理就3天时间,期间一直不断尝试,一直也没有解决,失败的频率很高

问题解决

1

1、尝试用10M大小的文件切片,偶然间右击查看文件属性,大小10M,占用空间12M,怀疑切片有问题。1024X1024X10,按这个大小进行文件切片,切出来的文件占用空间12M,采用其他的方法进行切片,1000X1000X10,这个大小进行分片。

2

2、nio的文件分片操作

			
	        fin = new FileInputStream(localFilePath + filename);
    	    fcin = fin.getChannel();
        	long size = fcin.size();
			//nio的文件大小最好不要使用file.length()
	
			//size是文件的大小,计算得到要切分为几片,为保证最后一片要大于5M的要求,将剩余的大小加到最后一片上去
            long partNum = size / partFileSize;
            long remain = size % partFileSize;
            long splitSize = partFileSize;
            long finallySize = partFileSize + remain;
复制代码

使用 buffer.flip();记性切片。最后一片带着remain

            //ByteBuffer buffer = ByteBuffer.allocate((int) partFileSize); //15M一片
            //int count = 1;
            //while (count <= partNum) {
            //    buffer.clear();
            //    if (count == partNum) {
            //        buffer = ByteBuffer.allocate((int) finallySize);
            //    }
            //    int flag = fcin.read(buffer);
            //    if (flag == -1) {
            //        break;
            //    }
            //    buffer.flip();
            //    fout = new FileOutputStream(localFilePath + count + filename);
            //    fcout = fout.getChannel();
            //    fcout.write(buffer);
            //    log.info("文件分片生成 共{}个 第{}个 文件名{}", partNum, count, localFilePath + count + filename);
            //    count++;
            //}
复制代码

后来我觉得 buffer.filp可能有问题,导致我分片的上传成功率非常低,换用transferTo 从开始位置开始切片,每次切splitSize的大小,最后一片切splitSize+remain

			long startPoint = 0;
            for (int i = 1; i <= partNum; i++) {
                fout = new FileOutputStream(localFilePath + i + filename);
                fcout = fout.getChannel();
                if (i == partNum) {
                    splitSize = finallySize;
                }
                fcin.transferTo(startPoint, splitSize, fcout);
                startPoint += splitSize;
                fcout.close();
                fout.close();
            }
复制代码

3

3、还有一个注意的点,就是文件的上传,开放平台写的是直接上传一个video的数组,其实不是数组,就是一个完整的文件outputStream.toByteArray。 先读到inputStream中,再到outputStream.toByteArray,输入输出使用不同的流,不然io就会觉得不安全,可能会给报错

                log.info("开始上传第{}个文件 路径{}", i, localFilePath + i + filename);
                inputStream = new FileInputStream(new File(localFilePath + i + filename));//与根据File类对象的所代表的实际文件建立链接创建fileInputStream对象
                outStream = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                int len = 0;
                while ((len = inputStream.read(buffer)) != -1) {
                    outStream.write(buffer, 0, len);
                }
                String uploadRst = douYinHttpService.douYinFilePost(uploadUrl + i, i + filename, outStream.toByteArray());
复制代码

请求头

HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.valueOf(MediaType.MULTIPART_FORM_DATA_VALUE));
        ContentDisposition co = ContentDisposition.builder("form-data").name(VIDEO).filename(filename).build();
        headers.setContentDisposition(co);

        HttpHeaders videoHeader = new HttpHeaders();
        videoHeader.setContentDispositionFormData(VIDEO, filename);
        ByteArrayResource bar = new ByteArrayResource(bytes);
        HttpEntity<ByteArrayResource> videoPart = new HttpEntity<>(bar, videoHeader);
        MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
        body.add(VIDEO, videoPart);

        HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity(body, headers);
        log.info("douYinFilePost 抖音File POST请求 url {}  参数 {}", url, videoPart);
        String content = null;
        try {
            content = restTemplate.postForObject(new URI(url), requestEntity, String.class);
复制代码

根据postman发送请求就能追到请求头是什么。

其他问题

文件的分片上传其实是上传的一个视频文件,比如用手机录制两个视频,5M以上(分片的要求文件要在5M以上),第一次 part-num是1,将视频上传了,第二次part-num是2上传第二个视频文件,最后complete完成上传,这种情况他其实只识别到第一个视频文件,账号发布视频以后发现视频的长度还是第一个的长度。

为什么会造成这种情况呢,因为第一片的上传完成后有视频的长度信息和结束标记位,后面的不管你上传再多的分片,他还是只能识别到第一个,以后的就不管了。

使用文件切割后,观察生成的分片之后的文件就会发现,其实第一个分片,windows在预览的时候能看出来是个视频文件,打开播放的时候能播放,到一个时间点以后就不能播放了,视频的长度也是总视频长度;而其他分片的视频文件,发现根本不能预览,双击打开之后也提示文件损坏。 如图:第一个是切片之前,紧挨着的是切之后第一个能预览能播放。其他啥也不行。 在这里插入图片描述

最终效果

换用1000100010这种切片方案,加nio的channel的transferTo方法,使用几个视频做切片测试,测试6个文件,其中5个能一次性就分片上传成功。最后一个分片之后多次上传都不成功。换1000100015这样进行切片,每片15M,一次上传成功。

遗留问题

后续引入重试机制,将发布不成功的视频按其他的分片大小进行切分,再次上传,写个次数限制,重试5次,多了实在还不行,上传失败的就给用户提示吧,我也没招了。

联系

尝试了4天,最终按这种方案解决了上传失败率太高的问题,基本能达到上传一个成功一个,不过也不能避免上传失败的情况,大神有什么指教可以公众号联系我。 后续想把网站完善下,弄上回复框,算是定一个小目标

个人网站 www.51pro.top

20210929后续来了

问题: 交付给业务使用后频繁出现分片上传不合法的对象id

1、0927考虑业务给发的视频都是高清的视频,一秒10M,码率高,思路一寻找视频是不是不标准的? 2、0928出现自己的视频也传不上去了,和高清没什么关系,非高清的视频只要切片都是不合法的对象id 3、0928出现一次上传成功,0929出现一次上传成功。其他出现不合法的对象ID,怀疑抖音接口有问题,毕竟自己的代码能上传成功。 4、0928、0929提交工单给提示uploadid需要自己encode一次。毕竟有上传成功的,怀疑抖音平台问题。

尝试解决

1、

0927追视频问题,vlc播放器加mediaInfo软件看视频区别,达到了29M每秒。普通的视频几十KB每秒 在这里插入图片描述 0927追一天没发现视频有什么问题。晚上发非高清的视频,发现切片也会失败

2、

0928所有视频只要出现分片上传都会失败,一整天上传尝试一百次其中一次出现成功,妈的这失败高达99%, 但是其中还有一次成功的啊,不怀疑自己的代码有问题。0929上午出现一次成功,更不怀疑自己代码有问题了。

3、

0929工单信息 在这里插入图片描述

2021年09月27日 11:24 不合法的对象id 到底是什么id ???按10M大小进行切片 分片上传返回不合法的对象id uploadID 到底要不要自己encode? 能不能电话联系一下 XXXXXXXXXXXXXXXXXX 已关闭 查看 2021年09月27日 19:55 「工单回复」: 您好,uploadID encode一次即可

2021年09月28日 17:13 回复给「工单」: logid 20210928170850010212070082390889A4 已经encode一次了 ,还是不行 为什么有的视频可以,高清的视频不可以呢 视频地址还是原来那个 图片链接:XXXXXXXXXX

2021年09月28日 17:22 回复给「工单」: 自己encode以后 能成功上传的视频都不能上传了 不加还能有成功的

2021年09月28日 17:23 回复给「工单」: 高清的视频 分片都不成功 不清晰的那种 分片都可以上传成功; 只要加上encode 全失败

2021年09月28日 17:23 回复给「工单」: 能不能技术人给打个电话

2021年09月28日 17:53 「工单回复」: 对于日志20210928170850010212070082390889A4,我们检查后发现,传入的upload_id被encode了两次,实际上只需encode一次即可

2021年09月28日 17:54 「工单回复」: 不主动encode 可以成功,就不要encode了,你使用的工具内部可能会自动帮你encode

2021年09月28日 17:54 「工单回复」: 高清视频上传不成功,请提供相应的logid

2021年09月28日 18:11 回复给「工单」: 20210928170850010212070082390889A4

2021年09月28日 18:14 「工单回复」: 你好20210928170850010212070082390889A4 这个是之前itemid encode两次导致出错的日志

2021年09月28日 18:27 回复给「工单」: 202109281824330101980671340F00654D

2021年09月28日 18:28 回复给「工单」: 这个logid呢 其实是直接拿的uploadid的返回值 看看这个是怎么回事

2021年09月28日 18:31 回复给「工单」: logid:202109281824330101980671340F00654D logid:20210928182358010198066232370058B1 20210928182324010212026091290049B2 看看这三个的分片上传都失败了 是为什么 图片链接:XXXXXXXXXXXXXXXXXXXXX

2021年09月28日 18:35 回复给「工单」: 高清视频上传不成功logid : 2021092818323801020204808429013C35 202109281833200102040482303D0105B7 2021092818340301021216203212013FDE 202109281834460102121860185201BE88

2021年09月28日 18:51 「工单回复」: 你好,辛苦再提供下上传视频部分的代码,以及upload_id 2021年09月28日 19:07 回复给「工单」: 视频地址 test-pinpaiyunyingbop-lingxi.oss-cn-beijing.aliyuncs.com//spreaduatf…

2021年09月28日 19:07 回复给「工单」: upload_id=@9VwC1+GVDss1K23yZdEvTM6v0zC8Nf2FPMAn/A3yKFQROPf10iLiLFIhgQby5DoKZq6NSUBH1aHz+2F7oSfViQ==

2021年09月28日 19:07 回复给「工单」: "logid":"202109281903490102120381024503F418"

2021年09月28日 19:08 回复给「工单」: 代码截图,代码是可以上传视频的 只是能偶然一次上传成功,99的概率上传失败 图片链接:XXXXXXXXXXX

2021年09月28日 19:09 回复给「工单」: 高清视频地址 test-pinpaiyunyingbop-lingxi.oss-cn-beijing.aliyuncs.com//spreaduatf…

2021年09月28日 19:11 回复给「工单」: 高清视频的upload_id=@9VwC1+GVDss1K23yZdEvTM6o0TPsPfnQO5NxoAvwJ1QROPn91Hi3LAwhgQby5DoKH3Rt+cf0jIRPLoxgvuchKA==&part_number=1 "logid":"2021092819101101021205920833049DCC"

2021年09月28日 19:14 回复给「工单」: 代码并不是说全部都不能上传成功 ,中间出现少次可以成功的,不过是99概率的失败 图片链接:XXXXXXXXXXXXXX

2021年09月28日 21:05 「工单回复」: 可以再提供下upload_id 部分的代码吗?包括给upload_id 做encode的操作的代码

2021年09月29日 08:01 回复给「工单」: /video/part/init/ 直接用的这个接口的返回值data里面的upload_id

2021年09月29日 08:22 回复给「工单」: 这个uploadid是可以用的 如果encode之后就会变成两次encode,之前一直用的没问题,自从9.26以后,每次上传都失败,都是不合法的对象id,26-29号之间只有一次分片上传成功,9点半左右贴uppload_id的代码

2021年09月29日 09:39 回复给「工单」: 这个代码用了一个月了,一直是没有问题的,27号左右出现分片上传都失败,昨天就成功一次 图片链接:XXXXXXXXXXXX

2021年09月29日 09:40 回复给「工单」: 接口返回的uoloadid,直接使用,可以上传

2021年09月29日 09:53 回复给「工单」: 前天 昨天的所有分片上传 成功过一次 其他全部失败 都是这个不合法的对象id

2021年09月29日 10:25 回复给「工单」: 追问一句 开放平台在一周以内有更新吗 8月份到9月中旬都是能正常使用的,也申请了生产环境的应用,最近这三天突然发现分片上传出问题

2021年09月29日 15:44 「工单回复」: 最近几次的请求的upload_id中存在 出现问题,建议使用原生的方法,自己主动encode upload_id,再次尝试请求

2021年09月29日 17:13 回复给「工单」: 获取upload_id的返回值 就是分片上传使用的id,在一周之前是没有出现这个不合法对象id的问题,最近3天出现的这个问题。在没有encode的情况下,今天还成功过一次; urlencoder.encode(upload_id)之后,从来没有成功过。而且工单中回复的说encode了两遍;为什么不encode能成功过1次,而encode之后却完全没有成功过,工单还回复加了两次?

2021年09月29日 22:18 回复给「工单」: 解决了 restTemplete的post方法源码中有对url进行转码的操作,操作了最后两位的等号 关闭工单吧

0929问题解决

1、工单一直提示是uploadid有问题,需要encode一次,尝试使用postman发送,一个月之前使用postman分片上传的时候,uploadid不需要encode就能上传成功,这次尝试高概率返回不合法的对象id,使用工具encode之后发现 居然上传成功了。 这个现象是完全超过认知,为什么以前不需要做的,都能上传成功,现在的都不行了?反而加密后竟然可以了。

2、继续代码中encode,尝试多次后,postman发动的encode uploadid之后的上传都能成功,可是代码中出现的encode之后的全部失败。 为什么 3、怀疑代码发送后出现其他操作给我转码了。查询发送请求的代码。跟请求,打断点。 发请求使用的是restTemplete,追进去看看 这里调用的是post直接传的url,而正好,抖音开放平台中的uploadid是url中的参数,往里追 在这里插入图片描述 最后发现这里对url进行了转码操作 在这里插入图片描述 url中含有uploadid 最后的两个等号转换了%3D,其他的东西没有转换,这导致我的参数就发生了变化。 4、我怎么去掉转码这一步操作呢?

        //UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url);
        //String content = restTemplate.postForObject(builder.build(false).toUri(), requestEntity, String.class);
复制代码

第一种思路,这样尝试几次还是不行。 5、妈的 不用restTemplate了,自己写httpClient

bytes是read的子节流的数组
 //public String originPost(String url, String filePath, String filename, byte[] bytes) throws Exception {
    //    String result = "";
    //    CloseableHttpClient httpClient = HttpClients.createDefault();
    //    CloseableHttpResponse response = null;
    //    try {
    //        HttpPost post = new HttpPost(url);
    //        //设置请求体
    //        //List<NameValuePair> content = new ArrayList<NameValuePair>();
    //        //content.add(new BasicNameValuePair("video", bytes.toString()));
    //        //UrlEncodedFormEntity e = new UrlEncodedFormEntity(content, "UTF-8");
    //        //post.setEntity(e);
    //       我这里尝试了好几种设置请求头的方案,用了好几个entry,追了几个Entity的实现类,尝试好几次后均失败---------------------------------
    //        MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();
    //        entityBuilder.addPart("video", new FileBody(new File("XXXXXXXXXXXXXXXXXXXXXXXXXXXX")));
    //        entityBuilder.setCharset(Charset.forName("UTF-8")).addBinaryBody("video", new FileInputStream(filePath), ContentType.MULTIPART_FORM_DATA, filename);
    //
    //        post.setEntity(entityBuilder.build());
    //        //设置请求头
    //        post.addHeader("Content-Type", MediaType.MULTIPART_FORM_DATA_VALUE);
    //        post.addHeader("Content-Disposition", "name=\"video\"; filename=" + filename);
    //
    //        //发送请求
    //        response = httpClient.execute(post);
    //        if (response != null && response.getStatusLine().getStatusCode() == 200) {
    //            org.apache.http.HttpEntity entity = response.getEntity();
    //            result = EntityUtils.toString(entity);
    //        }
    //    } catch (Exception e) {
    //        log.info("originPost", e.getMessage());
    //    }
复制代码

这几个写法一直返回的是系统正忙,请稍后再试,总觉得是自己的请求不对,请求头的参数没设置好。

心情实在是糟糕透了,很长时间没有弄好这个请求头,废了很长时间,都没整好,tcp http没学好,回去再自学去吧,不会写了。放弃。 如果有谁能把这个方法补充上也能发送成功。 后续哪位高手看见补上给留言,感激不尽 在这里插入图片描述

最终方案

还是使用restTemplate,尝试一下这个方案,找post的重载的方法,看看有没有不转码的方法。看到一个这个,传URI,不会转码

            content = restTemplate.postForObject(new URI(url), requestEntity, String.class);

复制代码

皆大欢喜!!! 成功 后续创建视频也是使用这个encode之后的uploadid,还是用URI,不让他转码,自己手动转。

优化

增加失败重试机制,多试几次,单次切片保持一个大小,多次切片的大小不同,第一次每片10M,第二次每片12M,依次涨点,最后还要保证最后一片的大小大于5M。 最后再来一次托底的操作,最后一次尝试如果小于100M,使用一次单片上传。大于100M最后一次尝试切片。

    private static final Map<Integer, Long> redoCountPartSizeMap = new HashMap<>();

    static {
        redoCountPartSizeMap.put(1, 1000 * 1000 * 10L);
        redoCountPartSizeMap.put(2, 1000 * 1000 * 12L);
        redoCountPartSizeMap.put(3, 1000 * 1000 * 13L);
        redoCountPartSizeMap.put(4, 1000 * 1000 * 14L);
        redoCountPartSizeMap.put(5, 1000 * 1000 * 15L);
        redoCountPartSizeMap.put(6, 1000 * 1000 * 18L);
    }
复制代码

总结

网络的文件下载到本地 本地文件切片 获取uploadid encode操作 分片上传,注意不能让http给转码 完成上传 创建视频。

2021-11-20 后续又来了 几天前发现有几个视频一直在请求审核状态,发现抖音平台视频状态细化了,从11.15以后状态码和之前的对不起来了,导致一直在请求审核状态。 看开放平台video_status i32 表示视频状态。1:细化为5、6、7三种状态;2:不适宜公开;4:审核中;5:公开视频;6:好友可见;7:私密视频

怎么看都怀疑是之前提交的一个工单 审核结束但返回状态是审核中的问题 再改改代码走起

猜你喜欢

转载自juejin.im/post/7076037434869284900