带有 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 服务。该服务有两个操作:

当我调用测试操作时,一切都按预期工作,并且我在服务输出上看到打印的消息。但是,当我尝试调用 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,可以使用以下工具进行测试,非常有用。

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>

解决问题