spring mvc rest protocol buffers http 406 not acceptable error
我正在使用具有REST支持的Spring MVC 4.1.5,以尝试使用Google协议缓冲区消息格式的网络服务。我已经看到很多帖子都提到了JSON格式的此问题,但都没有提到Google协议缓冲区格式。
我也没有看到Spring框架文档有一个protobufs的MediaType(更多内容在下面)我的代码发布在github
上
这是我的控制器代码(使用或不使用Produces = " application-xprotobuf "没有区别-相同的406不可接受的错误)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | @RestController @RequestMapping("/ws") @EnableWebMvc public class CustomerRestController { @Autowired private CustomerRepository customerRepository; //@RequestMapping(value="/customers/{id}", method = RequestMethod.GET, produces="application/x-protobuf") @RequestMapping(value="/customers/{id}", method = RequestMethod.GET) public CustomerProtos.Customer customer(@PathVariable Integer id) { return this.customerRepository.findById(id); } @Bean ProtobufHttpMessageConverter protobufHttpMessageConverter() { return new ProtobufHttpMessageConverter(); } private CustomerProtos.Customer customer(int id, String f, String l, Collection<String> emails) { String emailAddressString ="[email protected]"; for (String email : emails) { emailAddressString = email; break; } EmailAddress emailAddress = CustomerProtos.Customer.EmailAddress.newBuilder() .setType(CustomerProtos.Customer.EmailType.PROFESSIONAL).setEmail(emailAddressString).build(); return CustomerProtos.Customer.newBuilder().setFirstName(f).setLastName(l).setId(id).addEmail(emailAddress) // .addAllEmail(emailAddresses) .build(); } @Bean CustomerRepository customerRepository() { return new CustomerRepositoryImpl(); } } |
这是我的web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>demo</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <servlet> <servlet-name>rest</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>rest</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/rest-servlet.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> </web-app> |
这是我的pom.xml,请注意,我确实在此处添加了Google protobuf库,它们最终位于已部署的.war文件的WEB-INF / lib文件夹中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.test</groupId> demo</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <parent> <groupId>org.springframework.boot</groupId> spring-boot-starter-parent</artifactId> <version>1.3.0.RELEASE</version> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <start-class>demo.DemoApplication</start-class> <java.version>1.8</java.version> <jackson.version>2.5.3</jackson.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> spring-webmvc</artifactId> <version>4.2.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> spring-tx</artifactId> <version>4.2.0.RELEASE</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> jackson-databind</artifactId> </dependency> <dependency> <groupId>javax.servlet</groupId> javax.servlet-api</artifactId> </dependency> <dependency> <groupId>com.google.protobuf</groupId> protobuf-java</artifactId> <version>2.5.0</version> </dependency> <dependency> <groupId>com.googlecode.protobuf-java-format</groupId> protobuf-java-format</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> spring-boot-legacy</artifactId> <version>1.0.0.RELEASE</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> |
这是我的测试客户
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | package demo; import java.util.Arrays; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.IntegrationTest; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.ResponseEntity; import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.web.client.RestTemplate; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration public class DemoApplicationTests { @Configuration public static class RestClientConfiguration { @Bean RestTemplate restTemplate(ProtobufHttpMessageConverter hmc) { return new RestTemplate(Arrays.asList(hmc)); } @Bean ProtobufHttpMessageConverter protobufHttpMessageConverter() { return new ProtobufHttpMessageConverter(); } } @Autowired private RestTemplate restTemplate; @Test public void contextLoaded() { ResponseEntity<CustomerProtos.Customer> customer = restTemplate.getForEntity( "http://localhost:7001/demo-0.0.1-SNAPSHOT/ws/customers/2", CustomerProtos.Customer.class); System.out.println("customer retrieved:" + customer.toString()); } } |
当我使用mvn test从命令行运行客户端时
我收到以下错误
1 2 3 4 5 6 7 8 9 | Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.697 sec <<< FAILURE! - in demo.DemoApplicationTests contextLoaded(demo.DemoApplicationTests) Time elapsed: 0.037 sec <<< ERROR! org.springframework.web.client.HttpClientErrorException: 406 Not Acceptable at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:91) at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:641) at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:597) at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:557) at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:289) at demo.DemoApplicationTests.contextLoaded(DemoApplicationTests.java:42) |
我看到有人建议使用contentNegotiationManager
在我的rest-servlet.xml中,我有mvc:annotation驱动的标签
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> <context:component-scan base-package="demo" /> <mvc:annotation-driven /> </beans> |
此外,我还在演示包
中放入了webConfig.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | package demo; import org.springframework.context.annotation.Configuration; import org.springframework.http.MediaType; import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @Configuration @EnableWebMvc public class WebConfig extends WebMvcConfigurerAdapter { /** * Total customization - see below for explanation. */ @Override public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { configurer.favorPathExtension(false). favorParameter(true). parameterName("mediaType"). ignoreAcceptHeader(true). useJaf(false). defaultContentType(MediaType.TEXT_PLAIN). mediaType("xml", MediaType.APPLICATION_XML). mediaType("json", MediaType.APPLICATION_JSON). mediaType("x-protobuf", MediaType.ALL) ; } } |
无论是否带有webconfig.java(正在执行contentNegotationManager的工作),我都收到406不可接受的错误。
我无法在Spring 4.1.3甚至4.2.3 jar中找到MediaType.APPLICATION_XPROTOBUF。
因此,我将该值留给了MediaType.ALL(我认为应该可以吗?)
运行测试客户端时,我会在实际运行测试之前收到此消息。.
1 2 3 4 | 09:27:26.198 [main] DEBUG o.s.web.client.RestTemplate - Created GET request for"http://localhost:7001/demo-0.0.1-SNAPSHOT/ws/customers/2" 09:27:26.199 [main] DEBUG o.s.web.client.RestTemplate - Setting request Accept header to [application/x-protobuf, text/plain, application/xml, application/json] 09:27:26.245 [main] DEBUG o.s.web.client.RestTemplate - GET request for"http://localhost:7001/demo-0.0.1-SNAPSHOT/ws/customers/2" resulted in 406 (Not Acceptable); invoking error handler |
它清楚地显示了它的接受标头设置为也包含" application-xprotobuf "值。
不知道在这种情况下我想念的是什么。
我也遇到了相同的问题,因为控制器失败,
Spring Boot automatically registers
HttpMessageConverter beans so we need only define theProtobufHttpMessageConverter bean and it gets configured appropriately.
从字面上理解
,因为没有Spring Boot不会发生转换器注册。该bean已实例化,但从未在HttpMessageConverters列表中注册。
我已经通过显式注册
1 2 3 4 5 6 7 8 9 10 11 | @Configuration @EnableWebMvc @ComponentScan public class AppConfig extends WebMvcConfigurerAdapter { @Override public void configureMessageConverters(List<HttpMessageConverter< ? >> converters) { converters.add(new ProtobufHttpMessageConverter()); super.configureMessageConverters(converters); } } |
您不需要为此声明一个单独的bean(除非您计划显式调用它)。
还请注意,覆盖