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">
</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?