jihulab上传文件API初探

jihulab上传文件API初探

一波issue刚平,一波issue又起。

国庆假期最后一晚,小梁封楼3天。小梁解封后第二天,小史再次喜提3天封楼。

眼看他起高楼,眼看他楼封了。

连绵不绝的封楼,正如连绵不绝的水杉ISSUE。

记录下第一个比较正式的ISSUE任务。

需求是,当学生点击上传作业后,自动触发jihulab的API,将作业文件上传到jihulab的项目仓库。

参照极狐的API文档,api名称为commit,大概流程是发送POST请求,访问API,上传文件。

没学过计网,但是目测用不到很高深的知识,那就开冲。

通读了接口介绍,有个最大的疑问:接口是如何把文件传给服务器的?

首先尝试了自定义文件内容,新建文件,通过curl命令试验后发现可以上传。

接下来,第一反应,那要把文件通过记事本打开,然后把里面的内容作为新建文件的内容,创建文件吗?

尝试后,发现提交上去的是仍是一堆乱码,于是开始慌了,不会给的接口不对吧,难道只能在创建文件时,在参数中填写文件txt格式的内容吗?

于是开始了走偏路,带着对jihulab文档完备性的怀疑,开始查阅gitlab的英文文档,发现了一些乱七八糟的api:

1、import,这个api确实可以上传文件,但是却只能上传clone一个project时所生成的tar文件;

2、uploads,顾名思义,这个api是创建一个提交,当通过这个api提交一个文件,发现上传成功,并得到一个文件url,以为万事大吉时,却发现仓库中没有该文件。咨询锦路兄后得知,用该api上传的文件并不是存到指定项目的仓库中,而是存到指定项目的一个暂存区,我可以在评论、issue等jihulab的操作中通过url引用这个文件,但并不能在仓库中看到它。

3、file,这个api是gitlab英文文档独有而jihulab中文文档没有的,经过测试后发现,这个api其实就相当于名为commit的api中,将action定义为create的操作,通过先前的理解,这样只能新建文件时输入一些文本内容,并不能创建其他格式的文件。

于是迷茫了,难道还没有开放创建其他格式文件的api吗?带着疑问,求助了gitlab交流群,热心群友也将上面4个api分别介绍给了我,可惜,我反映了情况后,都表示没有能解答。突然,有个哥们说将文件编码成base64,然后再调用api即可实现,他以前实现过。

曙光,往往出现在极夜之后,云开后方见月明。这条反馈眼前一亮,也就是说,这条路是通的,终点是一个可以达到的目标。

本着交流的精神,我咨询了jihulab的官方客服小姐姐,小姐姐直接联系到了jihulab的开发人员,一串shell命令映入眼帘。

还是用commit api,只不过要改下encoding格式,从默认的text改成base64,图片也得先转成base64:

Demo:
cat test.png | base64 > test.base64

curl --request POST \
     --form "branch=main" \
     --form "commit_message=upload pic" \
     --form "start_branch=main" \
     --form "actions[][action]=create" \
     --form "actions[][file_path]=foo/test.png" \
     --form "actions[][encoding]=base64" \
     --form "actions[][content]=</root/test.base64" \
     --header "PRIVATE-TOKEN: xxxxxxxxxxx" \
     "https://gitlab.example.com/api/v4/projects/1/repository/commits"

拷到自己的云服务器中,回车,查看jihulab,成功上传!

原来通过curl命令上传其他格式文件需要通过base64编码,并且此时文件内容要填写文件路径。

下面的问题就是将该curl命令转换为java代码。

经由先前一个ISSUE中原神的提醒,curl命令可能并不会预装在服务器中;并且经过自己的实验,在win/macos/linux中curl命令的语法亦有不同,所以弃用通过java直接调用curl命令的方法。取而代之的,使用原神推荐的springboot提供的resttemple方法,通过resttemple发送post/get请求:

//使用表单提交,创建POST请求,编码选择base64,内容为文件转码的base64格式文件内容
                    MultiValueMap<String, String> jsonMap2= new LinkedMultiValueMap<>();
                    jsonMap2.add("branch","main");
                    jsonMap2.add("commit_message", "upload homework file");
                    jsonMap2.add("actions[][action]","create");
                    jsonMap2.add("actions[][content]",res);
                    jsonMap2.add("actions[][file_path]","homework/"+homework.getHomeworkId()+"_"+tag+"_"+originName);
                    jsonMap2.add("actions[][encoding]", "base64");
                    HttpEntity<MultiValueMap<String, String>> httpEntity2 = new HttpEntity<MultiValueMap<String, String>>(jsonMap2, httpHeaders);
                    RestTemplate restTemplate = new RestTemplate();
                    ResponseEntity<String> apiResponse = restTemplate.postForEntity
                            (
                                    uri,
                                    httpEntity2,
                                    String.class
                            );

                }

1、在MultiValueMap格式的map中设置请求内容data(甚至可以直接以字符串的方式发送表单形式)

2、在httpheaders中设置请求头

3、通过String.class解析返回参数

4、通过url字符串设置访问链接

其中,1和2组装成entity,和3、4一起,作为restTemplate.postForEntity的参数。

剩下的一些注意点,也解决了挺久:

1、在impl中的一个函数中,不仅需要post形式的commit接口,还需要get形式的repository查看项目接口。这时候如果controller中只写了@PostMapping(“/upload”),就会后端报错get方法无效。所以应该将其改为

@RequestMapping(value = "/upload",method = {RequestMethod. POST ,RequestMethod. GET })

以此使得该函数既能发送post请求,又能发送get请求。

2、resttemple理论上并没有get方法,只有postforentity方法,于是要使用一个exchange方法,在其中参数设置为HttpMethod.GET,通过一个拦截器(?暂未搞懂底层)将其捕获,并发送get请求。

3、文件需要编码为base64格式,这里通过getFileStream的方法,获取前端传来的mutipartfile格式文件的输入流,将文件输入流以byte为单位读到数组中,再通过Base64编码器将其编码为base64格式的字符串。

byte[] byt = null;
                byt = new byte[file.getInputStream().available()];
                file.getInputStream().read(byt);
                String res = new BASE64Encoder().encodeBuffer(byt);

4、由于jihulab的api的一些返回是以error的方式返回的,所以不能全都用判断返回字符串的方式判断逻辑,于是使用try…catch的方法设置整个逻辑流程(不优雅,但不知道如何改进)

后续加了群里的三位热心网友,发现其中一个小马哥还是在大连做devops的,还和王伟老师、张琰彬老师、小雅学姐、Frank学长有联系,世界真小!

如果你足够热爱,你总会遇到那些,同样足够热爱的人。

(pp老师对【水杉-jihulab】有更加深远的规划和蓝图,欲知后事如何,请看下回分解。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注