Wiremock 为 Spring Cloud Contract 存根运行程序返回错误的内容类型

问题描述 投票:0回答:3

我是第一次尝试 Spring-Cloud-Contract。我试图让我的客户端自动发现合同存根,但即使我的合同在响应上指定了“application/json”的内容类型,我从 WireMock 获得的内容类型也具有“application/octet”的内容类型'。我做错了什么?

我的服务中有一个简单的方法,它从

/status
端点返回这样的模型:

{
  "name": string,
  "status": string
}

我的合同是这样的:

import org.springframework.cloud.contract.spec.Contract

Contract.make {
    request {
        method('GET')
        headers {
            contentType(applicationJson())
        }
        url("/status")
    }

    response {
        status OK()
        body(
                name: "Demo",
                status: "RUNNING"
        )
        headers {
            contentType(applicationJson())
        }
    }
}

在我的客户端中,我有一个类使用 Spring

RestTemplate
来查询此端点:

@Component
public class StatusClient {

    private final RestTemplate restTemplate;

    public StatusClient(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    public Status getStatus() {
        return this.restTemplate
                .exchange("http://localhost:8080/status", HttpMethod.GET, null, Status.class)
                .getBody();
    }
}

@Data
class Status implements Serializable {
    private String name;
    private String status;
}

我的单元测试使用

@AutoConfigureStubRunner
从本地存储库中提取最新版本的合约,并对合约的响应进行断言(例如名称 = Demo,状态 = RUNNING)。

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureStubRunner(ids = {"com.example:contract-demo:+:8080"}, stubsMode = StubRunnerProperties.StubsMode.LOCAL)
public class StatusClientTests {

    @Autowired
    private StatusClient client;

    @Test
    public void testThatStatusReturnsSuccessfully() {
        Status result = this.client.getStatus();
        assertEquals("Demo", result.getName());
        assertEquals("RUNNING", result.getStatus());
    }
}

当我运行测试时,WireMock 会按预期报告收到的合同:

2018-05-31 11:36:49.919  INFO 14212 --- [tp1255723887-26] WireMock                                 : Request received:
127.0.0.1 - GET /status

User-Agent: [Java/1.8.0_161]
Connection: [keep-alive]
Host: [localhost:8080]
Accept: [application/json, application/*+json]



Matched response definition:
{
  "status" : 200,
  "body" : "{\"name\":\"Demo\",\"status\":\"RUNNING\"}",
  "headers" : {
    "contentType" : "application/json"
  },
  "transformers" : [ "response-template" ]
}

Response:
HTTP/1.1 200
contentType: [application/json]

但是当 RestTemplate 尝试反序列化它时,它会抛出异常,因为一旦它命中提取数据的方法,响应内容类型实际上是“application/octet”:

org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class com.example.contractclientdemo.Status] and content type [application/octet-stream]

    at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:119)
    at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:991)
    at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:974)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:725)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:680)
    at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:600)
    at com.example.contractclientdemo.StatusClient.getStatus(StatusClient.java:18)

我使用 Finchley.RC2 作为 Spring 云版本,

spring-cloud-starter-contract-stub-runner
是我除了
spring-boot-starter-test
之外的唯一测试依赖项。

我知道 WireMock 返回错误的内容类型,因为我深入调试了 Spring 中的 HttpMessageConverterExtractor 类,这就是

getContentType
方法在查询时返回的内容。

为什么 WireMock 在日志中报告了正确的内容类型,却返回了错误的内容类型?我怎样才能让它正确返回

application/json
以便我可以反序列化我的简单消息?

spring wiremock spring-cloud-contract
3个回答
1
投票

我遇到了和你完全相同的问题。我通过添加

解决了这个问题
headers {
  header 'Content-Type': 'application/json;charset=UTF-8'
}

回复。 您的回复中似乎有,虽然是以另一种方式写的,但这确实解决了我的情况的问题。所以这和它有关系。

在进行更改之前,curl 显示没有 Content-Type 响应标头:

curl -v -H“接受:application/json”本地主机:6565/products/ABC
* 尝试 127.0.0.1...
* TCP_NODELAY 设置
* 连接到本地主机 (127.0.0.1) 端口 6565 (#0)
获取/产品/ABC HTTP/1.1
主机:本地主机:6565
用户代理:curl/7.58.0
接受:application/json

HTTP/1.1 200 好
传输编码:分块
服务器:Jetty(9.2.z-SNAPSHOT)

与主机本地主机的连接 #0 保持不变

{  
  "price": {  
    "currencyCode": "EUR",  
    "value": "100.50"  
  },  
  "name": "Fake product"  
}

完成更改后,curl 返回此值,并且 RestTemplate 设法反序列化它。

HTTP/1.1 200 好
内容类型:application/json;charset=UTF-8
传输编码:分块
服务器:Jetty(9.2.z-SNAPSHOT)

这是我的工作合同:

import org.springframework.cloud.contract.spec.Contract
Contract.make {
    description "should return product information"
    request{
        method GET()
        url("/products/ABC")
    }
    response {
        status 200
        headers {
            header 'Content-Type': 'application/json;charset=UTF-8'
    }
        body([
          name: 'Fake product',
          price:[
              currencyCode: 'EUR',
              value: 100.50
          ]
        ])
    }
}

希望这有帮助


0
投票

我认为你应该将其作为 WireMock 中的问题提交。此外,您没有在请求中显式设置 application/json 内容类型标头。也许这是一个问题?另外,它不应该是内容类型作为响应存根中的标头名称吗?


0
投票

您需要将内容类型作为 xml 添加到模拟的响应正文中

        stubFor(post(urlMatching("/xyz"))
            .willReturn(ok("""
                            <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
                            <response>
                              <number>784658522</number>
                            </response>
                    """).withHeader("Content-Type", ContentType.XML.toString())));
© www.soinside.com 2019 - 2024. All rights reserved.