Jersey文件上传中FormDataContentDisposition获取文件名异常问题
问题定性
这不是FormDataContentDisposition的bug,属于使用场景兼容问题。
根因分析
- 部分旧版本Windows浏览器(如IE9及更早版本)、自定义开发的上传客户端,在构造
multipart/form-data请求的Content-Disposition头时,不会只传递上传文件的纯文件名,会直接把文件在客户端的本地完整全路径填充到filename字段中,Jersey只是如实解析了请求头里的原始值返回。 - 你拼接存储路径时,获取到的文件名自带Windows盘符标识,Windows系统的文件路径解析规则会优先识别路径中的盘符,忽略前面拼接的
c://temp//前缀,实际写入的路径就是客户端传来的全路径,自然不会出现在c:\temp目录下。
修复方案
只需要对getFileName()返回的原始值做一次纯文件名提取,过滤掉路径前缀即可,同时还能避免路径穿越漏洞:
import java.io.File; // 其他原有import保持不变 @Path("/files") public class FileUploadService { @POST @Path("/upload") @Consumes(MediaType.MULTIPART_FORM_DATA) @Produces({"text/plain","application/xml","application/json"}) public Response uploadPdfFile( @FormDataParam("file") InputStream fileInputStream, @FormDataParam("file") FormDataContentDisposition fileMetaData) throws Exception { String UPLOAD_PATH = "c://temp//"; try { // 新增:提取纯文件名,兼容Windows和Unix路径格式 String originalName = fileMetaData.getFileName(); // 方式1:用File类直接取文件名,简单便捷 String fileName = new File(originalName).getName(); // 可选额外校验:过滤路径穿越字符,避免恶意上传 if (fileName.contains("..") || fileName.contains("/") || fileName.contains("\\")) { throw new WebApplicationException("非法文件名"); } int read = 0; byte[] bytes = new byte[102400]; // 用处理后的纯文件名拼接路径 OutputStream out = new FileOutputStream(new File(UPLOAD_PATH + fileName)); while ((read = fileInputStream.read(bytes)) != -1) { out.write(bytes, 0, read); } out.flush(); out.close(); } catch (IOException e) { throw new WebApplicationException("Error while uploading file. Please try again !!"); } return Response.ok("Data uploaded successfully !!").build(); } }
额外注意事项
如果上传业务允许文件名重复,建议在纯文件名基础上额外拼接随机字符串/时间戳,避免同名文件覆盖。
内容的提问来源于stack exchange,提问作者andy tang
相关产品推荐
相关产品推荐

