当前位置:  开发笔记 > 编程语言 > 正文

spring mvc rest protocol缓冲http 406不可接受的错误

如何解决《springmvcrestprotocol缓冲http406不可接受的错误》经验,为你挑选了1个好方法。

我正在使用Spring MVC 4.1.5及其REST支持尝试使用谷歌协议缓冲区消息格式的Web服务.我看过很多帖子都提到了JSON格式的这个问题,但没有一个用google协议缓冲区格式.另外我没有看到Spring框架文档有一个用于protobufs的MediaType(下面有更多内容)我的代码发布在github上

这是我的控制器代码(使用或不使用produce ="application-xprotobuf"没有区别 - 相同406不可接受的错误)

@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 emails) {
        String emailAddressString = "defaultEmail@address.com";
        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



  demo
  
    index.html
    index.htm
    index.jsp
    default.html
    default.htm
    default.jsp
  



    rest
    
        org.springframework.web.servlet.DispatcherServlet
    
    1



    rest
    /*


    
        contextConfigLocation
        /WEB-INF/rest-servlet.xml
    

    
        org.springframework.web.context.ContextLoaderListener
    


这是我的pom.xml,请注意我在这里添加了谷歌protobuf库,他们最终在部署的.war文件的WEB-INF/lib文件夹中.



    4.0.0

    org.test
    demo
    0.0.1-SNAPSHOT
    war

    
        org.springframework.boot
        spring-boot-starter-parent
        1.3.0.RELEASE
    

    
        UTF-8
        demo.DemoApplication
        1.8
        2.5.3

    

    
        
            org.springframework
            spring-webmvc
            4.2.0.RELEASE
        
        
            org.springframework
            spring-tx
            4.2.0.RELEASE
        
        
            com.fasterxml.jackson.core
            jackson-databind
        
        
            javax.servlet
            javax.servlet-api
        
        
            com.google.protobuf
            protobuf-java
            2.5.0
        
        
            com.googlecode.protobuf-java-format
            protobuf-java-format
            1.2
        

        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
        

        
            org.springframework.boot
            spring-boot-legacy
            1.0.0.RELEASE
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    

这是我的测试客户端

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 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测试从命令行运行客户端时,我收到以下错误

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-driven标签



    
    
  

此外,我已经放入了演示包中的webConfig.java

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(我觉得应该有用吗?)

当我运行测试客户端时,我在实际运行测试之前收到此消息.

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"值.不知道在这种情况下我缺少什么.



1> yktoo..:

我遇到了与控制器失败相同的问题406: Not Acceptable.经过大量的跟踪后,我想出了示例中的语句:

Spring Boot会自动注册HttpMessageConverterbean,因此我们只需要定义ProtobufHttpMessageConverterbean并对其进行适当的配置.

从字面上理解,因为没有Spring Boot,就不会发生转换器注册.bean 实例化,但它从未在HttpMessageConverters列表中注册.

我通过显式注册ProtobufHttpMessageConverter实例解决了这个问题:

@Configuration
@EnableWebMvc
@ComponentScan
public class AppConfig extends WebMvcConfigurerAdapter {

    @Override
    public void configureMessageConverters(List> converters) {
        converters.add(new ProtobufHttpMessageConverter());
        super.configureMessageConverters(converters);
    }
}

您不需要为它声明一个单独的bean(除非您打算明确地调用它).

另请注意,覆盖configureMessageConverters()会禁用所有标准转换器; 如果您的意思是扩展库存转换器列表而不是替换它,请改写extendMessageConverters().

推荐阅读
低调pasta_730
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有