복붙노트

[SPRING] 봄 MVC + JSON = 406 허용되지 않음

SPRING

봄 MVC + JSON = 406 허용되지 않음

간단한 JSON 응답을 생성하려고합니다. 지금은 406 Not Acceptable 오류가 발생합니다. Tomcat은 "이 요청으로 식별 된 리소스는 요청"accept "헤더에 따라 수용 할 수없는 특성을 갖는 응답 만 생성 할 수 있습니다." 내 수락 헤더가

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

tomcat / lib에는 모든 Tomcat jars, Spring jars 및 jackson-all-1.9.0.jar가 있습니다. Tomcat 7에서 Spring 3.2.2를 사용하고 있습니다.

이 문제가 여러 번 논의 된 사실을 알고 있지만 해결 방법이 없습니다.

을 포함한다.

<web-app id="WebApp_ID" version="2.4" 
    xmlns="http://java.sun.com/xml/ns/j2ee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

  <display-name>Spring Web MVC Application</display-name>

  <servlet>
    <servlet-name>dispatcher</servlet-name>
        <servlet-class>
                  org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
        <url-pattern>*.htm</url-pattern>
  </servlet-mapping>

</web-app>

dispatcher-servlet.xml

<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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
     http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver" >
        <property name="prefix">
            <value>/WEB-INF/pages/</value>
        </property>
        <property name="suffix">
            <value>.jsp</value>
        </property>
    </bean>
 <context:component-scan base-package="com.smiechmateusz.controller" />
 <context:annotation-config />

    <mvc:annotation-driven />

</beans>

HelloWorldController.java

package com.smiechmateusz.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;

import com.smiechmateusz.dao.Foo;

@Controller
@RequestMapping("/")
public class HelloWorldController extends AbstractController{

    @Override
    protected ModelAndView handleRequestInternal(HttpServletRequest request,
        HttpServletResponse response) throws Exception {

        ModelAndView model = new ModelAndView("HelloWorldPage");
        return model;
    }

    @RequestMapping(value="foobar.htm", method = RequestMethod.GET)
    public @ResponseBody Foo getShopInJSON() {
        Foo f = new Foo();
        f.setX(1);
        f.setY(2);
        f.setDescription("desc");
        return f;
    }
}

Foo.java

package com.smiechmateusz.dao;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="foobaz")
public class Foo implements Serializable
{
    private int x, y;
    String description;
    int id;

    @Column(name = "x")
    public int getX() {
        return x;
    }
    public void setX(int x) {
        this.x = x;
    }
    @Column(name = "y")
    public int getY() {
        return y;
    }
    public void setY(int y) {
        this.y = y;
    }
    @Column(name = "description")
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }

    @Id @GeneratedValue
    @Column(name = "id")
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
}

이미 추가를 시도했습니다.

<bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="messageConverters">
          <list>
            <ref bean="jsonConverter"/>
          </list>
    </property>
</bean>

내 dispatcher-servlet.xml 또는 jakcson-all을 jackson-asl 및 jackson-core-asl로 변경했지만 결과는 동일했습니다.

해결법

  1. ==============================

    1.그것은 문제가되어야합니다. JSON은 application / json으로 제공됩니다. 이에 따라 Accept 헤더를 설정하면 적절한 응답을 얻어야합니다. (헤더를 설정할 수있는 브라우저 플러그인이 있는데, Firefox 용으로는 "포스터"가 가장 좋음)

    그것은 문제가되어야합니다. JSON은 application / json으로 제공됩니다. 이에 따라 Accept 헤더를 설정하면 적절한 응답을 얻어야합니다. (헤더를 설정할 수있는 브라우저 플러그인이 있는데, Firefox 용으로는 "포스터"가 가장 좋음)

  2. ==============================

    2.Maven과 최신 Jackson 코드를 사용하고 있다면 스프링 구성 XML 파일에서 Jackson 특정 구성을 모두 제거 할 수 있습니다 (여전히 annotation-driven 태그 가 필요합니다). 일부 pom.xml 파일 종속성. 종속성의 예는 아래를 참조하십시오. 이것은 나를 위해 일했고 나는 다음을 사용하고있다 :

    Maven과 최신 Jackson 코드를 사용하고 있다면 스프링 구성 XML 파일에서 Jackson 특정 구성을 모두 제거 할 수 있습니다 (여전히 annotation-driven 태그 가 필요합니다). 일부 pom.xml 파일 종속성. 종속성의 예는 아래를 참조하십시오. 이것은 나를 위해 일했고 나는 다음을 사용하고있다 :

  3. ==============================

    3.이 오류를 얻을 수있는 또 다른 방법은 공개 멤버가없는 클래스를 만드는 것입니다. 406이 시나리오에서는 꽤 쓸모없는 오류 메시지입니다.

    이 오류를 얻을 수있는 또 다른 방법은 공개 멤버가없는 클래스를 만드는 것입니다. 406이 시나리오에서는 꽤 쓸모없는 오류 메시지입니다.

  4. ==============================

    4.Spring 4에서는 @EnableWebMvc 만 추가합니다. 예를 들면 다음과 같습니다.

    Spring 4에서는 @EnableWebMvc 만 추가합니다. 예를 들면 다음과 같습니다.

    @Controller
    @EnableWebMvc
    @RequestMapping(value = "/articles/action", headers="Accept=*/*",  produces="application/json")
    public class ArticlesController {
    
    }
    
  5. ==============================

    5.다른 답변들도 나를 도왔습니다.

    다른 답변들도 나를 도왔습니다.

    나는 수십개의 Stackoverflow에 대한 대답을 읽을 수 없다. HttpMediaTypeNotAcceptableException, multipart 파일, ResponseBody, Accept headers를 설정하고, 생성하고, 소비한다.

    우리는 Spring 4.2.4와 Spring을 build.gradle에서 설정했습니다 :

    compile "com.fasterxml.jackson.core:jackson-core:2.6.7"
    compile "com.fasterxml.jackson.core:jackson-databind:2.6.7"
    

    다른 모든 컨트롤러에서는 모든 경로가 정상적으로 작동했으며 GET, POST, PUT 및 DELETE를 사용할 수있었습니다. 그런 다음 멀티 파트 파일 업로드 기능을 추가하고 새 컨트롤러를 만들었습니다. GET 라우트는 잘 동작하지만 POST와 DELETE는 그렇지 않습니다. 아무리 나는 여기에서 다른 해결책을 시도해 보았습니다. 그래서 저는 계속 406 Not Acceptable을 계속 지키고있었습니다.

    그렇다면 마침내 나는이 SO 답변을 우연히 발견 : HttpMediaTypeNotAcceptableException 던지는 봄 : URL 경로에 점으로 인해 수용 가능한 표현을 찾을 수 없습니다.

    라니즈의 대답과 모든 의견을 읽으십시오.

    그것은 모두 우리의 @RequestMapping 값으로 내려갔습니다 :

    @RequestMapping(value = "/audio/{fileName:.+}", method = RequestMethod.POST, consumes="multipart/*")
    public AudioFileDto insertAudio(@PathVariable String fileName, @RequestParam("audiofile") MultipartFile audiofile) {
    
        return audioService.insert(fileName, audiofile);
    }
    
    @RequestMapping(value = "/audio/{fileName:.+}", method = RequestMethod.DELETE)
    public Boolean deleteAudio(@PathVariable String fileName) {
    
        return audioService.remove(fileName);
    }
    

    @RequestMapping 값의 {fileName :. +} 부분은 우리의 경우 406을 허용하지 않습니다.

    Raniz의 답변에서 추가 한 코드는 다음과 같습니다.

    @Configuration
    public class ContentNegotiationConfig extends WebMvcConfigurerAdapter {
        @Override
        void configureContentNegotiation(final ContentNegotiationConfigurer configurer) {
            // Turn off suffix-based content negotiation
            configurer.favorPathExtension(false);
        }
    }
    

    2016 년 8 월 29 일 수정 :

    우리는 configurer.favorPathExtension (false)를 사용하는 데 어려움을 겪었습니다. 정적 SVG 이미지가로드되는 것을 중단했습니다. 분석 한 결과 Spring은 "image / svg + xml"대신에 content-type "application / octet-stream"을 사용하여 SVG 파일을 다시 UI로 보냈다. fileName을 쿼리 매개 변수로 보내 다음과 같이 해결했습니다.

    @RequestMapping(value = "/audio", method = RequestMethod.DELETE)
    public Boolean deleteAudio(@RequestParam String fileName) {
    
        return audioService.remove(fileName);
    }
    

    또한 configurer.favorPathExtension (false)도 제거했습니다. 또 다른 방법은 경로에 fileName을 인코딩하는 것이지만 추가 매개 변수 메서드를 사용하여 추가 부작용을 피할 수 있습니다.

  6. ==============================

    6.아래의 의존성을 사용하여 귀하의 pom

    아래의 의존성을 사용하여 귀하의 pom

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.5.3</version>
    </dependency>
    
  7. ==============================

    7.spring-mvc-config.xml에 Jackson에 대한 주석 바인딩을 등록해야한다. 예를 들면 다음과 같다.

    spring-mvc-config.xml에 Jackson에 대한 주석 바인딩을 등록해야한다. 예를 들면 다음과 같다.

    <!-- activates annotation driven binding -->
    <mvc:annotation-driven ignoreDefaultModelOnRedirect="true" validator="validator">
        <mvc:message-converters>
            <bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/>
            <bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"/>
            <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
        </mvc:message-converters>
    </mvc:annotation-driven>
    

    그런 다음 컨트롤러에서 다음을 사용할 수 있습니다.

    @RequestMapping(value = "/your_url", method = RequestMethod.GET, produces = "application/json")
    @ResponseBody
    
  8. ==============================

    8.그 문제는 RequestMapping (* foobar.htm)의 * .htm 확장자를 사용하는 것이 었습니다. footer.json 또는 다른 것으로 변경하십시오.

    그 문제는 RequestMapping (* foobar.htm)의 * .htm 확장자를 사용하는 것이 었습니다. footer.json 또는 다른 것으로 변경하십시오.

    정답의 링크 : https://stackoverflow.com/a/21236862/537246

    추신

    개발자가 A에서 Z까지 Spring의 전체 API를 알고 있다는 사실과 관련하여, 기본적으로 무언가를 수행하는 것은 Spring의 방식입니다. 그런 다음 세부 사항없이 "406 허용되지 않습니다."그리고 Tomcat의 로그는 비어 있습니다!

  9. ==============================

    9.확장 기능에 문제가 있는지 확인하십시오. 확장에 따라 spring은 content-type을 알아 낸다. url이 .com으로 끝나면 text / html을 content-type 헤더로 보냅니다. Spring의이 동작을 변경하려면 다음 코드를 사용하십시오.

    확장 기능에 문제가 있는지 확인하십시오. 확장에 따라 spring은 content-type을 알아 낸다. url이 .com으로 끝나면 text / html을 content-type 헤더로 보냅니다. Spring의이 동작을 변경하려면 다음 코드를 사용하십시오.

    @Configuration
    @Import(HibernateConfig.class)
    @EnableWebMvc
    // @EnableAsync()
    // @EnableAspectJAutoProxy
    @ComponentScan(basePackages = "com.azim.web.service.*",  basePackageClasses = { WebSecurityConfig.class }, excludeFilters = { @ComponentScan.Filter(Configuration.class) })
    public class WebConfig extends WebMvcConfigurerAdapter {
    
        @Override
        public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
            configurer.favorPathExtension(false).favorParameter(true).parameterName("mediaType").ignoreAcceptHeader(true).useJaf(false)
                    .defaultContentType(MediaType.APPLICATION_JSON).mediaType("xml", MediaType.APPLICATION_XML).mediaType("json", MediaType.APPLICATION_JSON);
        }
    
        @Bean(name = "validator")
        public Validator validator() {
            return new LocalValidatorFactoryBean();
        }
    }
    

    여기서는 favorPathExtension을 false로 설정하고 Default Content-type을 Application / json으로 설정합니다. 주의 : HibernateConfig 클래스는 모든 빈을 포함한다.

  10. ==============================

    10.오늘 나는 똑같은 문제를 너무 지나쳤다. 내 경우에는 web.xml에서

    오늘 나는 똑같은 문제를 너무 지나쳤다. 내 경우에는 web.xml에서

       <servlet-mapping>
            <servlet-name>spring</servlet-name>
            <url-pattern>*.html</url-pattern>
        </servlet-mapping>
    

    내 URL은 .html 확장자를 가지고 있습니다. 예 : ... / getUsers.html. 하지만 컨트롤러에서 JSON 데이터를 반환하고 있습니다. .html 확장자는 기본적으로 html로 수락 유형을 설정합니다.

    그래서 다음과 같이 변경했습니다.

    веб.хмл :

    <servlet-mapping>
        <servlet-name>spring</servlet-name>
        <url-pattern>*.html</url-pattern>
        <url-pattern>*.json</url-pattern>
    </servlet-mapping>
    

    URL :

    .../getUsers.json

    모든 것이 이제는 잘되고 있습니다. 희망이 도움이됩니다.

  11. ==============================

    11.추가해보십시오.

    추가해보십시오.

    @RequestMapping(method = RequestMethod.GET,headers = {"Accept=text/xml, application/json"})
    

    getShopInJSON ().

    그것은 나를 위해 일했습니다.

  12. ==============================

    12.어쩌면 POJO의 모든 필드에 Getter와 Setter가 필요할 수도 있습니다.

    어쩌면 POJO의 모든 필드에 Getter와 Setter가 필요할 수도 있습니다.

    나는이 문제에 따라 그것을 고쳤다.  참조 : 봄 MVC - HttpMediaTypeNotAcceptableException

    그리고 406은 버그를 수정하는 유용한 메시지가 아닙니다. 코드로 디버깅하고 예외가 지구상에 무엇인지 확인해야합니다.

  13. ==============================

    13.이것은 객체가 JSP로 허용되지 않기 때문입니다 ...

    이것은 객체가 JSP로 허용되지 않기 때문입니다 ...

    이 종속성을 추가하거나 jsp로 변환 된 다른 json 문자열을 보내십시오.

    예를 들면 이것을 pom에 추가하십시오.

    <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.6.2</version>
        </dependency>
    

    다음과 같은 코드를 사용하십시오 :

    @RequestMapping(value="foobar.htm", method = RequestMethod.GET)
        public @ResponseBody String getShopInJSON() {
            Foo f = new Foo();
            f.setX(1);
            f.setY(2);
            f.setDescription("desc");
            return new Gson().toJson(f); //converted object into json string
        }//return converted json string
    
  14. ==============================

    14.json 출력을 생성 / 수신하려고하는 것 같습니다. 당신의 접근 방식에 두 가지 문제점이 있습니다. 1) Accept 헤더에 application / json을 지정하지 않았습니다. 2) @RequestMapping에서 produce = "application / json"을 지정해야합니다.

    json 출력을 생성 / 수신하려고하는 것 같습니다. 당신의 접근 방식에 두 가지 문제점이 있습니다. 1) Accept 헤더에 application / json을 지정하지 않았습니다. 2) @RequestMapping에서 produce = "application / json"을 지정해야합니다.

  15. ==============================

    15.나는 대답으로 그것을 볼 수 없었다. 그래서 스프링 4.2를 사용하여 실수로 getson / setter를 삭제할 때 나는 Json으로 반환 될 것으로 기대했던 클래스에 대해이 오류를 받았다고 언급 할 것이라고 생각했다.

    나는 대답으로 그것을 볼 수 없었다. 그래서 스프링 4.2를 사용하여 실수로 getson / setter를 삭제할 때 나는 Json으로 반환 될 것으로 기대했던 클래스에 대해이 오류를 받았다고 언급 할 것이라고 생각했다.

  16. ==============================

    16.내 RequestMapping 값은 .html로 끝나며 다른 것이되어야합니다.

    내 RequestMapping 값은 .html로 끝나며 다른 것이되어야합니다.

    나는 그것을 .json으로 변경하려고 시도했고 그것은 나를 위해 일했다.

  17. ==============================

    17.비슷한 문제가있어 아래 코드를 사용하여 해결했습니다.

    비슷한 문제가있어 아래 코드를 사용하여 해결했습니다.

    public class ProductList {
    
        private List<Product> productList =  new ArrayList<Product>();
    
        @JsonProperty("data")
        @JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.WRAPPER_OBJECT)
        public List<Product> getProductList() {
            return productList;
        }
    public void setProductList(List<Product> productList) {
            this.productList = productList;
        }
    
    I am setting ProductList object in ResponseEntity object and returning from controller.
    
  18. ==============================

    18.내 클래스에 JsonSerialize 주석이 달렸고 include 매개 변수가 JsonSerialize.Inclusion.NON_DEFAULT로 설정되었습니다. 이로 인해 Jackson은 각 Bean 등록 정보의 기본값을 판별합니다. 나는 int를 리턴 한 bean 프라퍼티를 가졌다. 제 경우의 문제점은 bean getter가 유추 된 반환 유형 (즉 일반적인 메소드)이있는 메소드를 호출했기 때문입니다. 어떤 이상한 이유로이 코드가 컴파일되었습니다. 유추 된 반환 형식에 int를 사용할 수 없으므로 컴파일되지 않아야합니다. 나는 그 bean 속성에 대해 'int'를 'Integer'로 변경했고 더 이상 406을 얻지 못했습니다. 이상한 점은 Integer를 int로 다시 변경하면 코드가 컴파일되지 않습니다.

    내 클래스에 JsonSerialize 주석이 달렸고 include 매개 변수가 JsonSerialize.Inclusion.NON_DEFAULT로 설정되었습니다. 이로 인해 Jackson은 각 Bean 등록 정보의 기본값을 판별합니다. 나는 int를 리턴 한 bean 프라퍼티를 가졌다. 제 경우의 문제점은 bean getter가 유추 된 반환 유형 (즉 일반적인 메소드)이있는 메소드를 호출했기 때문입니다. 어떤 이상한 이유로이 코드가 컴파일되었습니다. 유추 된 반환 형식에 int를 사용할 수 없으므로 컴파일되지 않아야합니다. 나는 그 bean 속성에 대해 'int'를 'Integer'로 변경했고 더 이상 406을 얻지 못했습니다. 이상한 점은 Integer를 int로 다시 변경하면 코드가 컴파일되지 않습니다.

  19. ==============================

    19.이 상태가 리턴되는 또 다른 경우가 있습니다. Jackson 매퍼가 bean을 직렬화하는 방법을 알 수없는 경우입니다. 예를 들어, 동일한 부울 속성 인 isFoo () 및 getFoo ()에 대한 접근 자 메서드가 두 개있는 경우

    이 상태가 리턴되는 또 다른 경우가 있습니다. Jackson 매퍼가 bean을 직렬화하는 방법을 알 수없는 경우입니다. 예를 들어, 동일한 부울 속성 인 isFoo () 및 getFoo ()에 대한 접근 자 메서드가 두 개있는 경우

    getFoo ()를 제거하고 isFoo ()를 삽입하십시오. 그것은 나를 위해 일했다.

  20. from https://stackoverflow.com/questions/16335591/spring-mvc-json-406-not-acceptable by cc-by-sa and MIT license