Swagger 吐出 xml 响应而不是 json

Posted

技术标签:

【中文标题】Swagger 吐出 xml 响应而不是 json【英文标题】:Swagger spitting out xml response instead of json 【发布时间】:2013-10-01 09:01:46 【问题描述】:

春天我一周大。我正在使用 Spring + maven + Jackson 开发一个纯 RESTful API 服务。在探索一些最佳实践时,我遇到了this,因此我决定将 swagger 与 spring mvc(和 swaggerUI)一起用于文档。我经历了this 和this 教程来做我想做的事。一切都很顺利,直到我意识到在点击 /api-docs 后我得到了 XML 响应,而不是教程和其他地方的 JSON 响应。当我添加 SwaggerUI 时,这将无法正常工作。后来我发现here swaggerUI 需要 json。我总是可以在没有服务器集成的情况下返回并使用 swagger (https://github.com/wordnik/swagger-core/wiki/Adding-Swagger-to-your-API),但这并不能真正满足我的需求。

这里是 pom.xml 的内容:

<?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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.darshandzend</groupId>
<artifactId>swjs</artifactId>
<name>swjs</name>
<packaging>war</packaging>
<version>1.0.0-BUILD-SNAPSHOT</version>
<properties>
    <java-version>1.6</java-version>
    <org.springframework-version>3.1.1.RELEASE</org.springframework-version>
    <org.aspectj-version>1.6.10</org.aspectj-version>
    <org.slf4j-version>1.6.6</org.slf4j-version>
</properties>
<dependencies>
    <!-- Spring -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>$org.springframework-version</version>
        <exclusions>
            <!-- Exclude Commons Logging in favor of SLF4j -->
            <exclusion>
                <groupId>commons-logging</groupId>
                <artifactId>commons-logging</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>$org.springframework-version</version>
    </dependency>

    <!-- AspectJ -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>$org.aspectj-version</version>
    </dependency>

    <!-- Logging -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>$org.slf4j-version</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>jcl-over-slf4j</artifactId>
        <version>$org.slf4j-version</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>$org.slf4j-version</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.15</version>
        <exclusions>
            <exclusion>
                <groupId>javax.mail</groupId>
                <artifactId>mail</artifactId>
            </exclusion>
            <exclusion>
                <groupId>javax.jms</groupId>
                <artifactId>jms</artifactId>
            </exclusion>
            <exclusion>
                <groupId>com.sun.jdmk</groupId>
                <artifactId>jmxtools</artifactId>
            </exclusion>
            <exclusion>
                <groupId>com.sun.jmx</groupId>
                <artifactId>jmxri</artifactId>
            </exclusion>
        </exclusions>
        <scope>runtime</scope>
    </dependency>

    <!-- @Inject -->
    <dependency>
        <groupId>javax.inject</groupId>
        <artifactId>javax.inject</artifactId>
        <version>1</version>
    </dependency>

    <!-- Servlet -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.5</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.1</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>

    <!-- Test -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.7</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-mapper-asl</artifactId>
        <version>1.9.13</version>
    </dependency>
    <dependency>
        <groupId>com.wordnik</groupId>
        <artifactId>swagger-core</artifactId>
        <version>1.1-SNAPSHOT.121130</version>
    </dependency>

    <dependency>
        <groupId>com.mangofactory</groupId>
        <artifactId>swagger-springmvc</artifactId>
        <version>0.6.3</version>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <artifactId>maven-eclipse-plugin</artifactId>
            <version>2.9</version>
            <configuration>
                <additionalProjectnatures>
                    <projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
                </additionalProjectnatures>
                <additionalBuildcommands>
                    <buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
                </additionalBuildcommands>
                <downloadSources>true</downloadSources>
                <downloadJavadocs>true</downloadJavadocs>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>2.5.1</version>
            <configuration>
                <source>1.6</source>
                <target>1.6</target>
                <compilerArgument>-Xlint:all</compilerArgument>
                <showWarnings>true</showWarnings>
                <showDeprecation>true</showDeprecation>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>exec-maven-plugin</artifactId>
            <version>1.2.1</version>
            <configuration>
                <mainClass>org.test.int1.Main</mainClass>
            </configuration>
        </plugin>
    </plugins>
</build>

servlet 上下文:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

<!-- DispatcherServlet Context: defines this servlet's request-processing 
    infrastructure -->

<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />

<!-- Handles HTTP GET requests for /resources/** by efficiently serving 
    up static resources in the $webappRoot/resources directory -->
<resources mapping="/resources/**" location="/resources/" />

<!-- Resolves views selected for rendering by @Controllers to .jsp resources 
    in the /WEB-INF/views directory -->
<beans:bean
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <beans:property name="prefix" value="/WEB-INF/views/" />
    <beans:property name="suffix" value=".jsp" />
</beans:bean>

<context:component-scan base-package="com.darshandzend.swjs" />

<beans:bean class="com.mangofactory.swagger.configuration.DocumentationConfig" />
<context:property-placeholder location="classpath:/swagger.properties" />

swagger.properties

documentation.services.version=1.0
documentation.services.basePath=http://localhost:8080/swjs/

我在 chrome dev http 工具中尝试了 GET /api-docs/ ,并将“Accept”标头设置为“application/json”,效果很好。这是否意味着我必须手动设置请求标头?我添加 web.xml 以防万一。

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>

<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!-- Processes application requests -->
<servlet>
    <servlet-name>appServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>appServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

我认为 swagger 不需要任何特殊注释,因此我的 java 代码库保持不变。

这个问题是不是太长了?请原谅我,因为我是新来的。请编辑并提出建议。

控制器类:

@Api(value = "contacts", description = "contacts") // Swagger annotation
@Controller
@RequestMapping("/home")
public class HomeController 
@ResponseBody
  @RequestMapping(method=RequestMethod.GET)
  public Response select() 
    return new Response("success", "", "this is the humble abode of everything");
  

@ResponseBody
  @RequestMapping(value="/id",method=RequestMethod.GET)
  public Response get(@PathVariable String id) 
    return new Response("Success", "", id);
  

【问题讨论】:

你能展示你的Controller方法吗? 另外,请忽略@Api注解中的参数...代码不是很漂亮 您能否确认您在类路径中拥有 Jackson 库,最好是在 WAR 中? 当我点击我在控制器中定义的 API 之一时,我肯定会收到 JSON 响应。你能建议我怎么检查吗?另外,我注意到我正在使用来自“codehaus”的杰克逊,the sample example on github 使用来自“fasterxml”的杰克逊。这会有所作为吗? codehaus 罐子适用于 Jackson 1.9.x 版。从 2.0 版起,Jackson 使用 fasterxml jars。你可能会想要更新的版本——我认为现在没有理由用旧版本开发一些东西。它们也不能很好地协同工作 - 如果您的依赖项之一使用 fasterxml jar,并且您引入 codehaus jar,它肯定会搞砸 - 只有将加载一个 Jackson 引擎,而不是两个。 【参考方案1】:

Swagger-ui 不会为其 AJAX 请求设置 Accept 标头。不幸的是,如果没有接受标头或没有给出路径扩展名 (.json),swagger-springmvc 将返回 XML。

您可以手动将 JSON 接受标头添加到 swagger-ui 执行的每个请求。只需将以下 javascript 行添加到您的 swagger-ui index.html 文件中:

window.authorizations.add("Accept", 
    new ApiKeyAuthorization("Accept", "application/json", "header"));

这是我修改后的 index.html 文件:

<!DOCTYPE html>
<html>
<head>
  <title>Swagger UI</title>
  <link href='//fonts.googleapis.com/css?family=Droid+Sans:400,700' rel='stylesheet' type='text/css'/>
  <link href='css/highlight.default.css' media='screen' rel='stylesheet' type='text/css'/>
  <link href='css/screen.css' media='screen' rel='stylesheet' type='text/css'/>
  <script type="text/javascript" src="lib/shred.bundle.js"></script>
  <script src='lib/jquery-1.8.0.min.js' type='text/javascript'></script>
  <script src='lib/jquery.slideto.min.js' type='text/javascript'></script>
  <script src='lib/jquery.wiggle.min.js' type='text/javascript'></script>
  <script src='lib/jquery.ba-bbq.min.js' type='text/javascript'></script>
  <script src='lib/handlebars-1.0.0.js' type='text/javascript'></script>
  <script src='lib/underscore-min.js' type='text/javascript'></script>
  <script src='lib/backbone-min.js' type='text/javascript'></script>
  <script src='lib/swagger.js' type='text/javascript'></script>
  <script src='swagger-ui.js' type='text/javascript'></script>
  <script src='lib/highlight.7.3.pack.js' type='text/javascript'></script>
  <script type="text/javascript">
    $(function () 
      window.swaggerUi = new SwaggerUi(
      url: "http://localhost:8080/api-docs",
      dom_id: "swagger-ui-container",
      supportedSubmitMethods: ['get', 'post', 'put', 'delete'],
      onComplete: function(swaggerApi, swaggerUi)
        if(console) 
          console.log("Loaded SwaggerUI")
        
        $('pre code').each(function(i, e) hljs.highlightBlock(e));
      ,
      onFailure: function(data) 
        if(console) 
          console.log("Unable to Load SwaggerUI");
          console.log(data);
        
      ,
      docExpansion: "none"
    );

    window.authorizations.add("Accept", new ApiKeyAuthorization("Accept", "application/json", "header"));

    $('#input_apiKey').change(function() 
      var key = $('#input_apiKey')[0].value;
      console.log("key: " + key);
      if(key && key.trim() != "") 
        console.log("added key " + key);
        window.authorizations.add("key", new ApiKeyAuthorization("api_key", key, "query"));
      
    )
    window.swaggerUi.load();
  );

  </script>
</head>

<body>
<div id='header'>
  <div class="swagger-ui-wrap">
    <a id="logo" href="http://swagger.wordnik.com">swagger</a>

    <form id='api_selector'>
      <div class='input icon-btn'>
        <img id="show-pet-store-icon" src="images/pet_store_api.png" title="Show Swagger Petstore Example Apis">
      </div>
      <div class='input icon-btn'>
        <img id="show-wordnik-dev-icon" src="images/wordnik_api.png" title="Show Wordnik Developer Apis">
      </div>
      <div class='input'><input placeholder="http://example.com/api" id="input_baseUrl" name="baseUrl" type="text"/></div>
      <div class='input'><input placeholder="api_key" id="input_apiKey" name="apiKey" type="text"/></div>
      <div class='input'><a id="explore" href="#">Explore</a></div>
    </form>
  </div>
</div>

<div id="message-bar" class="swagger-ui-wrap">
  &nbsp;
</div>

<div id="swagger-ui-container" class="swagger-ui-wrap">

</div>

</body>

</html>

【讨论】:

我记得尝试过。那时一定是犯了句法错误。无论如何,这行得通。谢谢。 令人惊讶的是,这是一个错误,而且没有人在上游报告过它。我做到了:github.com/wordnik/swagger-ui/issues/388 我们在上游修复了错误github.com/wordnik/swagger-js/commit/… - 只需 3 小时。

以上是关于Swagger 吐出 xml 响应而不是 json的主要内容,如果未能解决你的问题,请参考以下文章

当 XML SOAP 响应中存在单个元素时,JSON 对象而不是数组

RESTful 响应如何在 Yii2 中返回 JSON 而不是 XML?

RESTful 响应如何在 Yii2 中返回 JSON 而不是 XML?

当试图打开Swagger-UI时只获得一个json Response

asmx 服务返回 xml 而不是 json

Swagger:在哪里为调用提供示例 json?