将文件从 REST Web 服务发送到客户端的正确方法是什么?

2022-08-31 09:21:27

我刚刚开始开发 REST 服务,但我遇到了一个困难的情况:将文件从我的 REST 服务发送到我的客户端。到目前为止,我已经掌握了如何发送简单数据类型(字符串,整数等)的窍门,但是发送文件是另一回事,因为有太多的文件格式,我甚至不知道我应该从哪里开始。我的REST服务是在Java上创建的,我使用的是泽西岛,我使用JSON格式发送所有数据。

我读过关于base64编码的文章,有些人说这是一种很好的技术,有些人说它不是因为文件大小问题。正确的方法是什么?以下是我的项目中的简单资源类的外观:

import java.sql.SQLException;
import java.util.List;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.UriInfo;

import com.mx.ipn.escom.testerRest.dao.TemaDao;
import com.mx.ipn.escom.testerRest.modelo.Tema;

@Path("/temas")
public class TemaResource {

    @GET
    @Produces({MediaType.APPLICATION_JSON})
    public List<Tema> getTemas() throws SQLException{

        TemaDao temaDao = new TemaDao();        
        List<Tema> temas=temaDao.getTemas();
        temaDao.terminarSesion();

        return temas;
    }
}

我猜发送文件的代码是这样的:

import java.sql.SQLException;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

@Path("/resourceFiles")
public class FileResource {

    @GET
    @Produces({application/x-octet-stream})
    public File getFiles() throws SQLException{ //I'm not really sure what kind of data type I should return

        // Code for encoding the file or just send it in a data stream, I really don't know what should be done here

        return file;
    }
}

我应该使用哪种类型的注释?我看到有人推荐一个使用,这是正确的方法吗?我发送的文件是特定的文件,因此客户端不需要浏览文件。任何人都可以指导我如何发送文件吗?我是否应该使用 base64 对其进行编码以将其作为 JSON 对象发送?或者不需要编码即可将其作为JSON对象发送?感谢您提供的任何帮助。@GET@Produces({application/x-octet-stream})


答案 1

我不建议在 base64 中对二进制数据进行编码并将其包装在 JSON 中。它只会不必要地增加响应的大小并减慢速度。

只需使用 GET 并使用 javax.ws.rs.core.Response 的工厂方法之一(JAX-RS API 的一部分,因此您不会被锁定在 Jersey 中)来提供您的文件数据:application/octect-stream

@GET
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response getFile() {
  File file = ... // Initialize this to the File path you want to serve.
  return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM)
      .header("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"" ) //optional
      .build();
}

如果你没有实际的对象,但一个 ,Response.ok(实体,mediaType)也应该能够处理它。FileInputStream


答案 2

如果你想返回一个要下载的文件,特别是如果你想与一些文件上传/下载的javascript库集成,那么下面的代码应该可以完成这项工作:

@GET
@Path("/{key}")
public Response download(@PathParam("key") String key,
                         @Context HttpServletResponse response) throws IOException {
    try {
        //Get your File or Object from wherever you want...
            //you can use the key parameter to indentify your file
            //otherwise it can be removed
        //let's say your file is called "object"
        response.setContentLength((int) object.getContentLength());
        response.setHeader("Content-Disposition", "attachment; filename="
                + object.getName());
        ServletOutputStream outStream = response.getOutputStream();
        byte[] bbuf = new byte[(int) object.getContentLength() + 1024];
        DataInputStream in = new DataInputStream(
                object.getDataInputStream());
        int length = 0;
        while ((in != null) && ((length = in.read(bbuf)) != -1)) {
            outStream.write(bbuf, 0, length);
        }
        in.close();
        outStream.flush();
    } catch (S3ServiceException e) {
        e.printStackTrace();
    } catch (ServiceException e) {
        e.printStackTrace();
    }
    return Response.ok().build();
}