问题描述
我们正在使用Spring(4.1.1。)实现REST API。对于某些HTTP请求,我们希望返回一个没有正文作为响应的头。但是,使用 ResponseEntity< Void>
似乎不起作用。当使用 MockMvc
测试调用时,将返回406(不可接受)。使用 ResponseEntity< String>
没有参数值( new ResponseEntity< String>(HttpStatus.NOT_FOUND)
)可以正常工作。
We are implementing a REST API with Spring (4.1.1.). For certain HTTP requests, we would like to return a head with no body as a response. However, using ResponseEntity<Void>
doesn't seem to work. When called with a MockMvc
test, a 406 (Not acceptable) is returned. Using ResponseEntity<String>
without a parameter value (new ResponseEntity<String>( HttpStatus.NOT_FOUND )
) works fine.
方法:
@RequestMapping( method = RequestMethod.HEAD, value = Constants.KEY )
public ResponseEntity<Void> taxonomyPackageExists( @PathVariable final String key ) {
LOG.debug( "taxonomyPackageExists queried with key: {0}", key ); //$NON-NLS-1$
final TaxonomyKey taxonomyKey = TaxonomyKey.fromString( key );
LOG.debug( "Taxonomy key created: {0}", taxonomyKey ); //$NON-NLS-1$
if ( this.xbrlInstanceValidator.taxonomyPackageExists( taxonomyKey ) ) {
LOG.debug( "Taxonomy package with key: {0} exists.", taxonomyKey ); //$NON-NLS-1$
return new ResponseEntity<Void>( HttpStatus.OK );
} else {
LOG.debug( "Taxonomy package with key: {0} does NOT exist.", taxonomyKey ); //$NON-NLS-1$
return new ResponseEntity<Void>( HttpStatus.NOT_FOUND );
}
}
测试用例(TestNG):
Test case (TestNG):
public class TaxonomyQueryControllerTest {
private XbrlInstanceValidator xbrlInstanceValidatorMock;
private TaxonomyQueryController underTest;
private MockMvc mockMvc;
@BeforeMethod
public void setUp() {
this.xbrlInstanceValidatorMock = createMock( XbrlInstanceValidator.class );
this.underTest = new TaxonomyQueryController( this.xbrlInstanceValidatorMock );
this.mockMvc = MockMvcBuilders.standaloneSetup( this.underTest ).build();
}
@Test
public void taxonomyPackageDoesNotExist() throws Exception {
// record
expect( this.xbrlInstanceValidatorMock.taxonomyPackageExists( anyObject( TaxonomyKey.class ) ) ).andStubReturn(
false );
// replay
replay( this.xbrlInstanceValidatorMock );
// do the test
final String taxonomyKey = RestDataFixture.taxonomyKeyString;
this.mockMvc.perform( head( "/taxonomypackages/{key}", taxonomyKey ).accept( //$NON-NLS-1$
MediaType.APPLICATION_XML ) ).andExpect( status().isNotFound() );
}
}
失败堆栈跟踪:
FAILED: taxonomyPackageDoesNotExist
java.lang.AssertionError: Status expected:<404> but was:<406>
at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:60)
at org.springframework.test.util.AssertionErrors.assertEquals(AssertionErrors.java:89)
at org.springframework.test.web.servlet.result.StatusResultMatchers$10.match(StatusResultMatchers.java:652)
at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:153)
at de.zeb.control.application.xbrlstandalonevalidator.restservice.TaxonomyQueryControllerTest.taxonomyPackageDoesNotExist(TaxonomyQueryControllerTest.java:54)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:84)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:714)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:901)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1231)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
at org.testng.TestRunner.privateRun(TestRunner.java:767)
at org.testng.TestRunner.run(TestRunner.java:617)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:334)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:329)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:291)
at org.testng.SuiteRunner.run(SuiteRunner.java:240)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1149)
at org.testng.TestNG.run(TestNG.java:1057)
at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:111)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:204)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:175)
推荐答案
当你返回没有正文的 ResponseEntity
时,Spring使用 ResponseEntity
返回类型声明中提供的type参数来决定身体类型。
When you return a ResponseEntity
without a body, Spring uses the type argument provided in the ResponseEntity
return type declaration to decide on a body type.
所以
public ResponseEntity<Void> taxonomyPackageExists( @PathVariable final String key ) {
该类型将 Void
。 Spring将循环遍历其所有已注册的 HttpMessageConverter
实例,并找到一个可以为 Void
类型编写正文的实例。由于不存在这样的 HttpMessageConverter
(对于默认配置),它将决定它不能产生可接受的响应,因此返回406 Not Acceptable HTTP响应。
that type will be Void
. Spring will then loop through all its registered HttpMessageConverter
instances and find one that can write a body for a Void
type. Since no such HttpMessageConverter
exists (for a default configuration), it will decide that it cannot produce an acceptable response and therefore return a 406 Not Acceptable HTTP response.
使用 ResponseEntity< String>
,Spring将使用 String
作为响应正文并找到 StringHttpMessageConverter
作为处理程序。由于 StringHttpMessageHandler
可以为任何 Accepted
媒体类型生成内容,因此它将能够处理 application / xml
您的客户请求。
With ResponseEntity<String>
, Spring will use String
as the response body and find StringHttpMessageConverter
as a handler. And since StringHttpMessageHandler
can produce content for any Accepted
media type, it will be able to handle the application/xml
that your client is requesting.
在(目前错误,但似乎建议 ResponseEntity<?>
),正文的类型将被推断为对象
。如果类路径中有正确的库,Spring将可以访问XML HttpMessageConverter
,它可用于生成 application / xml
表示类型对象
。
In iddy85's solution (which is currently wrong, but seems to suggest ResponseEntity<?>
), the type for the body will be inferred as Object
. If you have the correct libraries in your classpath, Spring will have access to a XML HttpMessageConverter
which it can use to produce application/xml
for the type Object
.
这篇关于Spring:使用ResponseEntity< Void>返回空的HTTP响应不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!