带有 XML 参数的 REST 服务操作上的 HTTP 错误 415 不支持的媒体类型 (Jersey + Jetty)
HTTP Error 415 Unsupported Media Type on REST service operation with an XML parameter (Jersey + Jetty )
我用 Jersey 和 Jetty 开发了一个 REST 服务。该服务有两个操作:
- GET 资源测试
- POST 在资源雇员上,它使用作为 XML
发送的 Employee 实例
当我调用测试操作时,一切都按预期工作,并且我在服务输出上看到打印的消息。但是,当我尝试调用 POST 操作时,出现 HTTP 错误 415.
要编译项目并生成 jar 文件,我正在使用 maven,这是 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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test.app</groupId>
<artifactId>Service</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven-compiler-plugin.version>3.6.0</maven-compiler-plugin.version>
<maven-shade-plugin.version>2.4.3</maven-shade-plugin.version>
<maven-resources-plugin.version>3.0.1</maven-resources-plugin.version>
<maven-clean-plugin.version>3.0.0</maven-clean-plugin.version>
<maven-war-plugin.version>3.0.0</maven-war-plugin.version>
<tomcat7-maven-plugin.version>2.1</tomcat7-maven-plugin.version>
<maven-jaxb2-plugin.version>0.12.1</maven-jaxb2-plugin.version>
<maven-surefire-plugin.version>2.19.1</maven-surefire-plugin.version>
<jersey.version>2.26</jersey.version>
<jetty.version>9.4.3.v20170317</jetty.version>
</properties>
<!-- DEPENDENCIES -->
<dependencies>
<!-- REST Service-->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-jetty-http</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
<version>${jersey.version}</version>
</dependency>
</dependencies>
<!-- BUILD -->
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy</id>
<phase>packaging</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<silent>true</silent>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>${maven-shade-plugin.version}</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>${project.artifactId}</finalName>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
这些是服务使用的两个类的代码:服务(服务实现)
package com.test.app;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.glassfish.jersey.servlet.ServletContainer;
@Path("/api")
public class Service {
@GET
@Path("test/")
public Response test() {
System.out.println("test invoked");
return Response.ok().build();
}
@POST
@Path("employee/")
@Consumes(MediaType.APPLICATION_XML)
@Produces(MediaType.APPLICATION_XML)
public Response getEmployee(Employee employee) {
employee.setEmployeeName(employee.getEmployeeName() + " Welcome");
return Response.status(Status.OK).entity(employee).build();
}
public static void main(String[] args) throws Exception {
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
int port = 46100;
Server jettyServer = new Server(port);
jettyServer.setHandler(context);
//org.eclipse.jetty.util.log.Log.getRootLogger().setDebugEnabled(true);
ServletHolder jerseyServlet = context.addServlet(ServletContainer.class, "/*");
jerseyServlet.setInitOrder(0);
// Tells the Jersey Servlet which REST service/class to load.
jerseyServlet.setInitParameter("jersey.config.server.provider.classnames", Service.class.getCanonicalName());
try {
jettyServer.start();
jettyServer.join();
} catch (Exception e) {
e.printStackTrace();
} finally {
jettyServer.destroy();
}
}
}
和Employee(作为参数传入函数的对象)
package com.test.app;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "Employee")
public class Employee {
String employeeName;
@XmlElement
public String getEmployeeName() {
return employeeName;
}
public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}
}
为了验证操作执行是否按预期工作,我 运行 以下 curl 命令:
curl -v -XPOST localhost:46100/api/employee -H "Content-type: application/xml" -d "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Employee>
<employeeName>Jack</employeeName>
</Employee>"
我得到的响应是 HTTP 错误 415。
我怀疑我遗漏了一些仅在运行时才需要的 Maven 文件的依赖性,其中包含从 XML 文件到实际 Employee 对象的转换。
我试过你的代码。绝对没问题。我在 Post REST 客户端中尝试过,它工作正常。 curl 命令有问题。在下面找到curl命令进行测试。
curl -XPOST http://localhost:46100/api/employee -H "Content-type: application/xml" -d "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Employee><employeeName>Jack</employeeName></Employee>"
我做了以下修改。
- 删除了 -v 选项
- 在 url
中添加了 http://
如果是RESTful webservice,可以使用以下工具进行测试,非常有用。
- Postman REST 客户端 (https://www.getpostman.com/downloads/)
- 失眠 REST 客户端 (https://insomnia.rest/)
maven-shade 插件配置错误。替换为
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>${maven-shade-plugin.version}</version>
<configuration>
<createDependencyReducedPom>true</createDependencyReducedPom>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"/>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
解决问题
我用 Jersey 和 Jetty 开发了一个 REST 服务。该服务有两个操作:
- GET 资源测试
- POST 在资源雇员上,它使用作为 XML 发送的 Employee 实例
当我调用测试操作时,一切都按预期工作,并且我在服务输出上看到打印的消息。但是,当我尝试调用 POST 操作时,出现 HTTP 错误 415.
要编译项目并生成 jar 文件,我正在使用 maven,这是 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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.test.app</groupId>
<artifactId>Service</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven-compiler-plugin.version>3.6.0</maven-compiler-plugin.version>
<maven-shade-plugin.version>2.4.3</maven-shade-plugin.version>
<maven-resources-plugin.version>3.0.1</maven-resources-plugin.version>
<maven-clean-plugin.version>3.0.0</maven-clean-plugin.version>
<maven-war-plugin.version>3.0.0</maven-war-plugin.version>
<tomcat7-maven-plugin.version>2.1</tomcat7-maven-plugin.version>
<maven-jaxb2-plugin.version>0.12.1</maven-jaxb2-plugin.version>
<maven-surefire-plugin.version>2.19.1</maven-surefire-plugin.version>
<jersey.version>2.26</jersey.version>
<jetty.version>9.4.3.v20170317</jetty.version>
</properties>
<!-- DEPENDENCIES -->
<dependencies>
<!-- REST Service-->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-jetty-http</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<version>${jetty.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
<version>${jersey.version}</version>
</dependency>
</dependencies>
<!-- BUILD -->
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy</id>
<phase>packaging</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<silent>true</silent>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>${maven-shade-plugin.version}</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>${project.artifactId}</finalName>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
这些是服务使用的两个类的代码:服务(服务实现)
package com.test.app;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.glassfish.jersey.servlet.ServletContainer;
@Path("/api")
public class Service {
@GET
@Path("test/")
public Response test() {
System.out.println("test invoked");
return Response.ok().build();
}
@POST
@Path("employee/")
@Consumes(MediaType.APPLICATION_XML)
@Produces(MediaType.APPLICATION_XML)
public Response getEmployee(Employee employee) {
employee.setEmployeeName(employee.getEmployeeName() + " Welcome");
return Response.status(Status.OK).entity(employee).build();
}
public static void main(String[] args) throws Exception {
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
int port = 46100;
Server jettyServer = new Server(port);
jettyServer.setHandler(context);
//org.eclipse.jetty.util.log.Log.getRootLogger().setDebugEnabled(true);
ServletHolder jerseyServlet = context.addServlet(ServletContainer.class, "/*");
jerseyServlet.setInitOrder(0);
// Tells the Jersey Servlet which REST service/class to load.
jerseyServlet.setInitParameter("jersey.config.server.provider.classnames", Service.class.getCanonicalName());
try {
jettyServer.start();
jettyServer.join();
} catch (Exception e) {
e.printStackTrace();
} finally {
jettyServer.destroy();
}
}
}
和Employee(作为参数传入函数的对象)
package com.test.app;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "Employee")
public class Employee {
String employeeName;
@XmlElement
public String getEmployeeName() {
return employeeName;
}
public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}
}
为了验证操作执行是否按预期工作,我 运行 以下 curl 命令:
curl -v -XPOST localhost:46100/api/employee -H "Content-type: application/xml" -d "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Employee>
<employeeName>Jack</employeeName>
</Employee>"
我得到的响应是 HTTP 错误 415。
我怀疑我遗漏了一些仅在运行时才需要的 Maven 文件的依赖性,其中包含从 XML 文件到实际 Employee 对象的转换。
我试过你的代码。绝对没问题。我在 Post REST 客户端中尝试过,它工作正常。 curl 命令有问题。在下面找到curl命令进行测试。
curl -XPOST http://localhost:46100/api/employee -H "Content-type: application/xml" -d "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Employee><employeeName>Jack</employeeName></Employee>"
我做了以下修改。
- 删除了 -v 选项
- 在 url 中添加了 http://
如果是RESTful webservice,可以使用以下工具进行测试,非常有用。
- Postman REST 客户端 (https://www.getpostman.com/downloads/)
- 失眠 REST 客户端 (https://insomnia.rest/)
maven-shade 插件配置错误。替换为
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>${maven-shade-plugin.version}</version>
<configuration>
<createDependencyReducedPom>true</createDependencyReducedPom>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"/>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
解决问题