web-dev-qa-db-ja.com

Spring MVC + JSON = 406 Not Acceptable

シンプルなJSONレスポンスを生成しようとしています。現在、406 Not Acceptableエラーが表示されます。 Tomcatは、「このリクエストによって識別されたリソースは、リクエストの「accept」ヘッダーに従って受け入れられない特性を持つ応答のみを生成できます」と言います。 Acceptヘッダーは

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

Tomcat/libには、すべてのTomcat jar、Spring jar、およびjackson-all-1.9.0.jarがあります。 Tomcat 7でSpring 3.2.2を使用しています。

私はこの問題が何度も議論されてきたことを知っていますが、解決策はありません。

web.xml

<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>

to my dispatcher-servlet.xml or changingjakcson-alltojackson-asl およびjackson-core-aslが、出力は同じでした。

50
Mateusz

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

それが問題になるはずです。 JSONはapplication/jsonとして提供されます。それに応じてAcceptヘッダーを設定すると、適切な応答が得られます。 (ヘッダーを設定できるブラウザプラグインがあります。Firefoxの "Poster"が最適です)

18

Mavenと最新の Jackson code を使用している場合、Spring構成XMLファイルからJackson固有の構成をすべて削除できます(注釈駆動型タグ<mvc:annotation-が必要です) driven />)、pom.xmlファイルにJacksonの依存関係をいくつか追加するだけです。依存関係の例については、以下を参照してください。これは私のために働いて、私は使用しています:

  • Apache Maven 3.0.4(r1232337; 2012-01-17 01:44:56-0700)
  • org.springframeworkバージョン3.1.2.RELEASE
  • spring-securityバージョン3.1.0.RELEASE。

    ...<dependencies>
    ...
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.2.3</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.2.3</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.2.3</version>
        </dependency>
        ...
    </dependencies>...
    
39
KSev

このエラーを取得するもう1つの方法は、パブリックメンバーのないクラスを作成することです。 406 unacceptableは、このシナリオではほとんど役に立たないエラーメッセージです。

20
Doo Dah

他の答えはどれも私を助けませんでした。

406 Not Acceptable、HttpMediaTypeNotAcceptableException、multipart file、ResponseBody、Acceptヘッダーの設定、produces、consumsなどに関するStackoverflowの回答を多数読みました。

Build.gradleでSpringBootとJacksonを構成したSpring 4.2.4がありました。

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

すべてのルートはotherコントローラーで正常に機能し、GET、POST、PUT、およびDELETEを使用できます。その後、マルチパートファイルアップロード機能の追加を開始し、新しいコントローラーを作成しました。 GETルートは正常に機能しますが、POSTおよびDELETEは機能しませんでした。 SOでここからさまざまな解決策を試しても、406 Not Acceptableを取得し続けました。

そして最後に私はこのSO答えに出くわしました: Spring throwing HttpMediaTypeNotAcceptableException:url pathのドットのために許容可能な表現を見つけることができませんでした

ラニスの答えとすべてのコメントを読んでください。

すべてが@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 Not Acceptableが発生しました。

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をエンコードすることもできますが、さらなる副作用を避けるためにクエリパラメーターメソッドを選択しました。

10

Spring 4では、次のように@EnableWebMvcのみを追加します。

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

}
8
Nguyen Viet

あなたのPOMで以下の依存関係を使用してください

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.5.3</version>
</dependency>
6
Nirbhay Rana

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
5
alain.janinm

私は、問題がRequestMappingの*。htm拡張機能の使用にあったと思われます(foobar.htm)。 footer.jsonまたは他の何かに変更してみてください。

正解へのリンク: https://stackoverflow.com/a/21236862/537246

追伸.

デフォルトでは、開発者がSpringのAPI全体をAからZまで知っているということに関して、デフォルトで何かをするのはSpringのやり方です。そして、詳細なしでただ「406 not accept」であり、Tomcatのログは空です!

4
Demwis

今日、私も同じ問題を経験しました。私の場合、web.xmlには

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

私のURLは.html拡張子を持っています。例:.../getUsers.html。しかし、コントローラーでJSONデータを返しています。 .html拡張子は、デフォルトで受け入れタイプをhtmlに設定します。

そこで、次のように変更しました。

web.xml:

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

RL:

.../getUsers.json

すべてが正常に動作しています。それが役に立てば幸い。

2
vissu

拡張機能に問題があることを確認してください。拡張子に応じて、springはcontent-typeを把握できます。 URLが。comで終わる場合、コンテンツタイプヘッダーとしてtext/htmlを送信します。 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クラスにはすべてのBeanが含まれています。

2
Azim

これは、オブジェクトがjspで受け入れられないためです...

この依存関係またはその他の変換されたJSON文字列をjspに追加...

たとえば、これを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
1
aditya Goyal

追加してみてください

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

getShopInJSON()

それは私のために働いた。

1
Shubham

POJOのすべてのフィールドにGetterとSetterが必要な場合があります。

この問題に応じて修正しました。参照: Spring MVC-HttpMediaTypeNotAcceptableException

また、406はバグを修正するのに役立つメッセージではありません。コードをデバッグして、例外が何であるかを確認する必要があります。

1
Dai Kaixian

このステータスが返される別のケースがあります:ジャクソンマッパーがBeanをシリアル化する方法を見つけられない場合。たとえば、同じブール型プロパティにisFoo()getFoo()の2つのアクセサーメソッドがある場合。

getFoo()を削除し、isFoo()を追加しました。それは私のために働いた。

0
The Java Guy

私はここで答えを見ることができなかったので、Jsonとして返されることを期待していたクラスのゲッター/セッターを誤って削除したときに、春4.2を使用してこのエラーを受け取ったことに言及すると思います。

0
jwv

私のRequestMapping値は。htmlで終わっていましたが、これは何か違うはずです。

。jsonに変更してみましたが、うまくいきました。

0
Swapneel

私は同様の問題を抱えており、以下のコードを使用して解決しました

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.
0
Sachin

クラスにJsonSerializeの注釈が付けられ、includeパラメーターがJsonSerialize.Inclusion.NON_DEFAULTに設定されました。これにより、ジャクソンは各Beanプロパティのデフォルト値を決定しました。 intを返すBeanプロパティがありました。私の場合の問題は、Beanゲッターが、戻り値の型が推測されるメソッド(つまり、ジェネリックメソッド)を呼び出すことでした。何らかの奇妙な理由で、このコードはコンパイルされました。推論された戻り値の型にintを使用できないため、コンパイルすべきではありません。そのBeanプロパティの 'int'を 'Integer'に変更し、406を取得しなくなりました。奇妙なことに、Integerをintに戻すとコードがコンパイルに失敗します。

0
Jared Simon

Json出力を生成/受信しようとしているようです。あなたのアプローチには2つの問題があります。 1)Acceptヘッダーでapplication/jsonを指定しなかった2)@RequestMappingでproduces = "application/json"を指定する必要がある

0
Balaji Katika