上传文件服务与web服务分离

业务场景:
1. 后端服务为java web应用,使用tomcat容器,多实例集群化部署。
2. 前端使用nginx作为后端应用的反向代理。

业务需求:
现在需要在java web应用端上传文件,同时还要能支持文件下载。

设计方案:
1. 文件应该专门使用文件服务器进行存储,在数据库中存储文件下载链接即可。
2. tomcat容器本身不擅长做文件上传下载的事情,所以最好将文件上传下载的功能与web服务分离,比如使用nginx作为文件服务器。

具体实现:
通常,针对简单的应用,可以使用NFS,在web端上传文件后直接写到文件服务器;或者将文件上传到web应用之后,再将文件同步到文件服务器。
不论是通过NFS或者任何其他同步工具的方式,都存在文件中转的过程,必须先将文件通过web应用进行上传保存,再同步到文件服务器。中间可能存在同步出错或延时,也存在扩展性不好的问题。
所以,设计实现方案如下:

1. 使用http协议通过web表单方式上传文件。
2. 在文件服务器上部署web服务器,专门用于文件上传。
3. 通常在web应用中上传文件时,除了上传文件数据,还需要传递一些文字。文字保存在数据库中,文件保存在服务器上,同时将生成文件下载链接保存在数据库。
4. 通过MD5校验文件内容,避免相同文件因为文件名不同而被恶意上传导致大量垃圾文件占满磁盘空间。

结合实际的业务需求,我们的上传文件流量不是很大,所以还是直接使用tomcat作为文件上传的web服务。文件下载使用nginx。
另外,为了避免需要通过在session中保存数据带来的问题,尽量将参数保存在request进行传递。举个例子:
通常在tomcat中会将用户登录的数据保存在session中,便于进行用户合法性验证,而文件上传时请求是在文件服务器上处理,无法获取到tomcat中的session对象。
为了解决这个问题,可以将session中的数据通过request传递到页面,在文件上传时又通过参数的方式传递给文件服务器。
直接传递参数存在安全漏洞,应该将参数进行加密处理。

特别注意:
经过验证,分离web服务和文件上传服务是可行的,但是因为存在跨域问题,所以在文件上传服务中必须要设置消息头:Access-Control-Allow-Origin。
具体的Servlet代码如下:

public class FileUploadServlet extends HttpServlet {
    @Override
    protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setHeader("Access-Control-Allow-Origin", "*"); //在options方法中设置跨域消息头
        super.doOptions(req, resp);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //处理文件上传逻辑
    }
}


【参考】
https://segmentfault.com/q/1010000007377501  站点做动静分离,如何处理用户上传文件呢?
http://www.cnblogs.com/rainy-shurun/p/5407085.html 上传文件服务器与web内容服务分离
http://www.cnblogs.com/xdp-gacl/p/4200090.html JavaWeb学习总结(五十)——文件上传和下载
https://stackoverflow.com/questions/304268/getting-a-files-md5-checksum-in-java Getting a File's MD5 Checksum in Java

posted @ 2017-07-19 17:58  nuccch  阅读(3167)  评论(0编辑  收藏  举报