带有 XML 参数的 REST 服务操作上的 HTTP 错误 415 不受支持的媒体类型(Jersey + Jetty)

Posted

技术标签:

【中文标题】带有 XML 参数的 REST 服务操作上的 HTTP 错误 415 不受支持的媒体类型(Jersey + Jetty)【英文标题】:HTTP Error 415 Unsupported Media Type on REST service operation with an XML parameter (Jersey + Jetty ) 【发布时间】:2019-10-08 22:50:16 【问题描述】:

我使用 Jersey 和 Jetty 开发了一个 REST 服务。该服务有两个操作:

获取资源测试 在使用以 XML 形式发送的 Employee 实例的资源员工上发布 POST

当我调用测试操作时,一切都按预期工作,并且我在服务输出中看到了打印的消息。但是,当我尝试调用 POST 操作时,我收到 HTTP 错误 415。

编译项目并生成我正在使用maven的jar文件,这是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>

而这些是服务使用的两个类的代码:Service(服务实现)

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 对象的转换。

【问题讨论】:

能否在进行休息调用时提供 Content-type 作为 application/xml 并在 getEmployee 方法中添加 @Produces(MediaType.APPLICATION_XML) 我得到了同样的结果。我编辑问题以在 curl 命令上添加标题 在 getEmployee 方法中添加 @Produces(MediaType.APPLICATION_XML)。添加后检查是否工作正常。 糟糕!我在以前的版本上尝试过,我认为它已经存在了。刚加回来,问题依旧 Add the service file transformer 到你的 maven shade 插件配置 【参考方案1】:

我试过你的代码。绝对没问题。我在 Post REST Client 中尝试过,它工作正常。 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 选项 在网址中添加了 http://

如果是 RESTful webservice,您可以使用以下工具进行测试,这些工具非常有用。

Postman REST 客户端 (https://www.getpostman.com/downloads/) Insomnia REST 客户端 (https://insomnia.rest/)

【讨论】:

检查并告诉我,我在 windows 机器上使用 curl 命令进行测试。 查看此链接,您将了解。 github.com/debjava/jetty-jersey-rest 如果你使用eclipse,可以将项目导入为maven项目。 我正在尝试从 github 链接运行项目,但遇到了同样的问题 有什么问题?【参考方案2】:

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>

解决问题

【讨论】:

以上是关于带有 XML 参数的 REST 服务操作上的 HTTP 错误 415 不受支持的媒体类型(Jersey + Jetty)的主要内容,如果未能解决你的问题,请参考以下文章

如果流被释放,带有 Stream 参数的 WCF REST 服务会抛出 400

使用 alamofire 将带有 JSON 对象和查询参数的 POST 请求发送到 REST Web 服务

带有查询字符串参数的 Rails 动作缓存

Tomcat Web 服务器上的 Spring REST 服务

带有 REST API 的 CQRS

Rest和Restful & http