Spring Cloud Contract:Groovy DSL如何指定Multipart请求Part的Content-Type
解决Spring Cloud Contract处理multipart/mixed请求的Content-Type指定问题
我之前也碰到过这个问题!当用Spring Cloud Contract处理带多个@RequestPart的multipart请求时,默认的Groovy DSL写法确实不会自动给每个Part指定Content-Type,得手动在契约里配置每个Part的请求头才行。
针对你的控制器方法,这里给出正确的Groovy DSL契约写法,能精准指定每个请求Part的Content-Type:
Contract.make { request { method POST() url "/posts" multipart( // 配置header文件Part,指定Content-Type为对应文件类型(这里用image/jpeg举例) header: named( content(file("header.jpg")), headers: [ "Content-Type": "image/jpeg", "Content-Disposition": "form-data; name=header; filename=header.jpg" ] ), // 配置photo文件Part photo: named( content(file("photo.png")), headers: [ "Content-Type": "image/png", "Content-Disposition": "form-data; name=photo; filename=photo.png" ] ), // 配置info的JSON Part,指定Content-Type为application/json info: named( content('{"title": "Test Post", "content": "Hello World"}'), headers: [ "Content-Type": "application/json", "Content-Disposition": "form-data; name=info" ] ) ) } response { status OK() body('"ok"') headers { contentType applicationJson() } } }
关键细节说明:
- 用
multipart块包裹所有请求Part,每个Part通过named方法来定义,这样就能为单个Part单独设置请求头(包括Content-Type)。 - 对于文件类型的Part(header和photo):
- 用
file("xxx")指定测试用的文件,这个文件要放在和契约文件同级的目录下(比如契约在src/test/resources/contracts/posts,文件也要放在这里)。 - 必须设置
Content-Disposition头,其中name要和控制器@RequestPart的参数名完全一致,filename是上传时的文件名。
- 用
- 对于JSON类型的
infoPart:- 直接传入符合格式的JSON字符串作为content,然后指定
Content-Type为application/json,同样要保证Content-Disposition的name和参数名一致。
- 直接传入符合格式的JSON字符串作为content,然后指定
生成的测试代码效果
配置完成后,自动生成的MockMvc测试代码会正确为每个Part设置Content-Type,大概长这样:
// given: MockMvcRequestSpecification request = given() .header("Content-Type", "multipart/mixed") .multiPart("header", "header.jpg", resourceLoader.getResource("classpath:contracts/posts/header.jpg").getInputStream(), "image/jpeg") .multiPart("photo", "photo.png", resourceLoader.getResource("classpath:contracts/posts/photo.png").getInputStream(), "image/png") .multiPart("info", "{\"title\": \"Test Post\", \"content\": \"Hello World\"}", "application/json"); // when: ResponseOptions response = given().spec(request).post("/posts"); // then: assertThat(response.statusCode()).isEqualTo(200); assertThat(response.header("Content-Type")).isEqualTo("application/json"); assertThat(response.body().asString()).isEqualTo("\"ok\"");
额外注意事项
- 确保测试文件存在于正确路径,否则生成的测试会因找不到文件报错。
- 如果你的
Json是自定义类型,要保证契约里的JSON字符串能被正确反序列化为该类型。 Content-Disposition的name必须和控制器方法的@RequestPart参数名严格匹配,否则Spring无法正确绑定参数。
内容的提问来源于stack exchange,提问作者MoOFueL
相关产品推荐
相关产品推荐

