调用Docker /v2/{name}/manifest/{tag} API推送镜像时报manifest invalid错误如何解决
问题修复方案
核心错误原因
你遇到的manifest invalid, invalid format length错误来自两个代码逻辑的共性问题:发送的manifest内容被错误转义/修改,以及Content-Type和实际manifest格式不匹配。
Shell脚本错误点&修复
错误点
curl的-d参数使用了单引号包裹$manifests变量,且额外加了多余双引号:
- 单引号内的shell变量不会展开,实际发送的是字面量
"$manifests",而非真实的manifest内容 - 多余的双引号会额外增加无效字符,导致manifest格式校验失败
修复后的代码
#! /bin/bash getManifestsUrl="http://localhost:5001/v2/registry/manifests/1" putManifestsUrl="http://localhost:5002/v2/registry/manifests/1" # 先获取manifest和对应的Content-Type contentType=$(curl -s -I "$getManifestsUrl" | grep -i 'content-type' | awk -F': ' '{print $2}' | tr -d '\r') manifests=$(curl -s -X GET "$getManifestsUrl") echo "$manifests" # PUT时直接传递原始manifest,使用源返回的Content-Type result=$(curl -X PUT -H "Content-Type:$contentType" -d "$manifests" "$putManifestsUrl") echo "$result"
Java代码错误点&修复
错误点
- GET请求时设置了
Content-Type头,该头对GET请求无意义,应该设置Accept头指定接收的manifest类型 - 从日志可以看到源站返回的manifest实际是
application/vnd.docker.distribution.manifest.v1+prettyjws格式,但PUT时硬编码了v2+json的Content-Type,格式和内容不匹配导致校验失败
修复后的代码
String name = "registry"; String tag = "1"; // get /v2/{name}/manifests/{tag} impl String url = String.format(fromHost + "/v2/%s/manifests/%s", name, tag); HttpHeaders httpHeaders = new HttpHeaders(); // GET请求设置Accept头,指定可接收的manifest类型 httpHeaders.set(HttpHeaders.ACCEPT, "application/vnd.docker.distribution.manifest.v2+json, application/vnd.docker.distribution.manifest.v1+prettyjws"); HttpEntity<String> httpEntity = new HttpEntity<>(null, httpHeaders); ResponseEntity<String> resp = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class); // 获取源站返回的真实Content-Type String contentType = resp.getHeaders().getFirst(HttpHeaders.CONTENT_TYPE); System.out.println(contentType); String manifests = resp.getBody(); // put /v2/{name}/manifests/{tag} impl httpHeaders.clear(); // 直接使用源站返回的Content-Type,不要硬编码 httpHeaders.set(HttpHeaders.CONTENT_TYPE, contentType); httpEntity = new HttpEntity<>(manifests, httpHeaders); resp = restTemplate.exchange(toHost + "/v2/registry/manifests/1", HttpMethod.PUT, httpEntity, String.class); System.out.println(resp);
额外注意事项
- 不要对获取到的manifest字符串做任何转义、格式化、缩进修改,否则会破坏哈希校验和格式结构
- 如果manifest包含签名信息,修改内容会导致签名失效,也会触发校验失败
- 确保PUT请求的Content-Length自动计算正确,不要手动指定错误的长度值
内容的提问来源于stack exchange,提问作者hello
相关产品推荐
相关产品推荐

