我们正在使用Spring(4.1.1。)实现REST
API。对于某些HTTP请求,我们希望返回没有正文的头作为响应。但是,使用ResponseEntity<Void>
似乎无效。通过MockMvc
测试调用时,返回406(不可接受)。使用ResponseEntity<String>
不带参数的值(new ResponseEntity<String>( HttpStatus.NOT_FOUND )
)工作正常。
方法:
@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):
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)
注意:对于问题4.1.1.RELEASE中提到的版本,这是正确的。
Spring MVC ResponseEntity
通过来处理返回值HttpEntityMethodProcessor
。
当ResponseEntity
值未设置主体(如您的代码段中的情况)时,将HttpEntityMethodProcessor
尝试根据处理程序方法ResponseEntity
签名中的返回类型的参数确定响应主体的内容类型@RequestMapping
。
因此对于
public ResponseEntity<Void> taxonomyPackageExists( @PathVariable final String key ) {
该类型将是Void
。HttpEntityMethodProcessor
然后将遍历其所有已注册HttpMessageConverter
实例,并找到可以为某种Void
类型编写主体的实例。根据您的配置,可能找不到,也可能找不到。
如果确实找到任何内容,则仍然需要确保将使用与请求Accept
标头中提供的类型匹配的Content-
Type编写相应的正文application/xml
。
如果在所有这些检查之后都不HttpMessageConverter
存在,Spring MVC将决定它无法产生可接受的响应,因此返回406 Not
Acceptable HTTP响应。
使用ResponseEntity<String>
,Spring将String
用作响应主体并查找StringHttpMessageConverter
作为处理程序。并且由于StringHttpMessageHandler
可以产生任何媒体类型的内容(Accept
标头中提供),因此它将能够处理application/xml
您的客户端所请求的内容。
从那以后,Spring MVC已更改为仅如果ResponseEntity
NOT中的主体为,则仅返回406 null
。如果您使用的是Spring
MVC的最新版本,则您不会在原始问题中看到该行为。
在iddy85的解决方案中(似乎暗示ResponseEntity<?>
了这一点),人体的类型将推断为Object
。如果您的类路径中有正确的库,即。杰克逊(版本>
2.5.0)及其XML扩展,SpringMVC将MappingJackson2XmlHttpMessageConverter
可以使用它来application/xml
为type
生成Object
。 他们的解决方案仅在这些条件下有效。 否则,由于与我上述相同的原因,它将失败。
问题内容: 在控制器中,我创建json数组。如果我还可以的话: 但我需要返回JSON数组和HTTP状态代码: Eclipse在XXX行中看到错误: 如何返回json + http回复?我的工作代码用于返回一个json对象+ http状态代码: 问题答案: 现在我回来了。我不知道更好的解决方案,但是可以。
问题内容: 我有以下Spring Security配置: 我期望以下逻辑:未经身份验证的用户将被重定向到。Spring会显示默认的Tomcat 403页面,而不是该页面。我也尝试过自定义,尽管没有成功。 如何在访问失败时实施自定义逻辑? 问题答案: AccessDeniedHandler仅适用于经过身份验证的用户。未经身份验证的用户的默认行为是重定向到登录页面(或适用于所使用的身份验证机制的任何内
我想使用GooglePlaceAPI和自动完成视图。我有开发者控制台上的android和浏览器密钥。但当我尝试这些键API时,它返回空响应。 Logcat: D/Volley:[2651]a.a:请求的HTTP响应= 我的代码: 在onpostexecute日志中: 我是新来的google地方api,请帮我找到什么是错误的。
问题内容: 我有一个Spring MVC方法,返回一个。根据检索到的特定数据, 有时 需要将数据流返回给用户。其他时候,它将返回除流之外的其他内容,有时还会返回重定向。我绝对希望它是一个流而不是字节数组,因为它可能很大。 当前,我使用以下代码片段返回流: 不幸的是,这不允许Spring 数据实际填充响应中的HTTP标头。这是有道理的,因为我的代码在Spring接收之前写入了。 某种程度上让Spri
你知道我在这里做错了什么吗?我怎么能让它工作。?!
我正在尝试对远程服务器进行api调用,最初,我遇到以下错误: