【问题标题】:Consuming muiltipart POST data in JAX-RS REST Service在 JAX-RS REST 服务中使用多部分 POST 数据
【发布时间】:2015-09-26 19:44:04
【问题描述】:

我有一个 jax-rs REST 服务,使用 JEE 7(部署在 glassfish 中),它具有处理资源上的 HTTP POST 的方法:

@POST
@Path(value="{dId}")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.APPLICATION_JSON)
public Response sendStatus(@Context HttpServletRequest request)

我尝试将多部分数据提取为:

Collection<Part> parts = request.getParts();
if(parts==null || parts.isEmpty()){
        lg.warn("Empty/non-existent parts in request body!");
        return sendBadRequestError(sp);
}

然后我尝试使用 RestClient(来自 wiztools.org)模拟客户端多部分 POST 请求,其中至少包含 2 个不同内容类型的部分(边界分隔符由 RESTClient 工具自动设置)。

我在 Wireshark 中验证它是从 RESTClient 发送的正确请求(没有格式错误的数据包等)。

然而,所有的请求似乎都命中了包含 Empty/non-existent parts in request body 消息的块,表明在请求中没有找到任何部分。

在发布之前,我在 Stackoverflow 中搜索了很多次,所有示例/解决方案都与上传文件/图像的用例有关,而我正在处理的情况并非如此。

我的 rest 服务只消费一个多部分请求,它可以由一个包含 JSON 数据的部分组成,另一部分包含简单的字符串或其他 JSON 数据。

有什么遗漏 - 请帮忙?。是否有其他技术来解析命中 REST 服务的多部分数据?

请指教。

谢谢。 J

【问题讨论】:

  • JSR-339 的第 9 章说明了哪些类型可以与 @Context 一起使用。如果您改用@FormParam,它会起作用吗?还是使用Request(docs.oracle.com/javaee/7/api/javax/ws/rs/core/Request.html)接口代替HttpServletRequest?
  • 我想 Jersey 已经读取了输入流。使用 Jersey 多部分 API,而不是直接访问 HttpServletRequest。见Multipart Support
  • 感谢 MartijnBurger 和 peeskillet 的建议。让我尝试这些选项并返回。
  • @MartijnBurger:我发现 Request (docs.oracle.com/javaee/7/api/javax/ws/rs/core/Request.html) API 不太容易使用,而且一开始Glance 似乎并没有以一种简单的方式提取多部分实体实体的机制。不确定这是否也是 API 的意图。我没有使用@FormParam,而是使用了org.glassfish.jersey.media.multipart.FormDataParam。两者的问题在于,如果我们不知道可以从请求中预期的正文部分的数量(在多部分请求中),则使用它不是通用的。感谢您抽出宝贵时间 - 这些指针帮助我以不同的方式思考!

标签: rest glassfish jax-rs multipart java-ee-7


【解决方案1】:

感谢来自@peeskillet 的指针,我使用 Jersey 多部分 API 来获取多部分实体的句柄。

为了帮助遇到同样问题的其他人,我列出了完整的解决方案:

  1. 在容器中为您的应用启用“MultiPart”功能。这对于所需读取器/写入器的可用性是必要的。如何做到这一点在Jersey 2 injection source for multipart formdata 中有明确说明
  2. 然后资源方法被定义为

    @POST
    @Path(value="{dId}")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    @Produces(MediaType.APPLICATION_JSON)
    public Response sendStatus(FormDataMultiPart multipart){
    ....
    ...
       Map<String, List<FormDataBodyPart>> parts = multipart.getFields();
       if(parts==null || parts.isEmpty()){
           lg.warn("Empty/non-existent parts in request body!");
           return sendBadRequestError(sp);
       }
    
       for(List<FormDataBodyPart> p: parts.values()){
             FormDataBodyPart bp = p.get(0);
             lg.info("\t body part name {}",bp.getName());
             lg.info("\t body part value {}",bp.getValue());            
              ....//do your real stuff here
        }
    
     }
    

而且宾果游戏有效!。

另外说明:使用 RESTClient GUI 工具时,请确保您没有明确设置 Content-Type 和 Boundary,因为该工具会自动设置。

希望这对某人有所帮助。

ps:我如何为 peeskillet 的答案投票?

【讨论】:

  • 是的。 JAX-RS 规范的一些实现(Jersey、Apache CXF)为此实现了专有解决方案。然而,问题是如何使用 JAX-RS 来做到这一点。正如您在这张票中看到的,这是一个正在等待执行的请求java.net/jira/browse/JAX_RS_SPEC-413
  • Ps:在 meta.stackoverflow.com 上查找并提出这些问题 您需要至少 15 的声誉才能为评论点赞。我赞成你的问题和答案,它应该给你足够的支持 cmets。
猜你喜欢
  • 2016-06-30
  • 1970-01-01
  • 1970-01-01
  • 2019-08-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多