Dubbo在2.6版本后合并了dubbox的resteasy代码后,可以支持rest风格的接口发布,但是在使用form表单上传文件的时候,获取的文件名称是乱码。

下面通过对源码分析一下原因,并提供一种可行的解决方法。

首先是一个resteasy上传的使用代码

@POST
@Path("/upload")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Override
public Object uploadfile(MultipartFormDataInput input, @Context HttpServletRequest request, @Context HttpServletResponse response) {
System.out.println("进入业务逻辑");
// MultipartFormDataReader
Map<String, Object> map = null; Map<String, List<InputPart>> uploadForm = input.getFormDataMap();
//取得文件表单名
List<InputPart> inputParts = uploadForm.get("file"); final String DIRCTORY = "D:/temp/datainput/";
initDirectory(DIRCTORY);
InputStream inputStream = null;
OutputStream outStream = null;
for (InputPart inputPart : inputParts) {
try {
// 文件名称
String fileName = getFileName(inputPart.getHeaders());
inputStream = inputPart.getBody(InputStream.class, null);
//把文件流保存;
File file = new File(DIRCTORY + fileName);
byte[] buffer = new byte[inputStream.available()];
inputStream.read(buffer);
outStream = new FileOutputStream(file);
outStream.write(buffer);
} catch (IOException e) {
e.printStackTrace();
}finally {
if(null != inputStream){
try {
inputStream.close();
} catch (IOException e) {
}
}
if(null != outStream){
try {
outStream.close();
} catch (IOException e) {
}
}
} } return Response.ok().build();
}

resteasy文件上传使用的Consumes使用的mediattype类型是MULTIPART_FORM_DATE【@Consumes(MediaType.MULTIPART_FORM_DATA)】

这个mediatype使用的Provider使用的是org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataReader,其readForm的入口为

   public MultipartFormDataInput readFrom(Class<MultipartFormDataInput> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException, WebApplicationException
{ String boundary = mediaType.getParameters().get("boundary");
if (boundary == null) throw new IOException(Messages.MESSAGES.unableToGetBoundary());
MultipartFormDataInputImpl input = new MultipartFormDataInputImpl(mediaType, workers);
input.parse(entityStream);
return input;
}

在跟入上面代码的parse方法 input.parse(entityStream)中的new BinaryMessage()构造函数中,MultipartInputImpl对http的head进行了解析

private static class BinaryMessage extends Message
{
private BinaryMessage(InputStream is) throws IOException, MimeIOException
{
try {
MimeStreamParser parser = new MimeStreamParser(null); StorageProvider storageProvider;
if (System.getProperty(DefaultStorageProvider.DEFAULT_STORAGE_PROVIDER_PROPERTY) != null) {
storageProvider = DefaultStorageProvider.getInstance();
} else {
StorageProvider backend = new CustomTempFileStorageProvider();
storageProvider = new ThresholdStorageProvider(backend, 1024);
}
parser.setContentHandler(new BinaryOnlyMessageBuilder(this, storageProvider));
parser.parse(is); // 此处未解析代码,未传入指定的字符串编码方式
} catch (MimeException e) {
throw new MimeIOException(e);
} }
}

在行 parser.parse(is);中,采用的是apache-mime4j-1.6版本的流解析器,由于MultipartInputImpl在调用apache-mime4j的解析方法,没有可指定字符编码的方法,此处编码的设置传递会丢失。(PS:MultipartInputImpl中的defaultPartCharset,可以通过拦截器request.setAttribute(InputPart.DEFAULT_CHARSET_PROPERTY, ENCODING_UTF_8);进行指定)。

后续未指定字符编码的调用链中,apache-mime4j对上传内容的解析采用了默认的ASCII编码进行处理,对应RawField.parseBody()

 private String parseBody() {
int offset = colonIdx + 1;
int length = raw.length() - offset;
return ContentUtil.decode(raw, offset, length);
}

该decode方法中使用的是写死的ASCII编码进行处理

public static String decode(ByteSequence byteSequence, int offset,
int length) {
return decode(CharsetUtil.US_ASCII, byteSequence, offset, length);
}

所以看到这里,就了解了为什么文件名称会是乱码的了,大概也知道其他地方通过拦截器设置编码格式解决不了文件名称乱码的问题了。

所以可行的解决方法可以是(亲测可用),将apache-mime4j-1.6的源码导入工程中,并且修改ContentUtil的decode方法,如下:

public static String decode(ByteSequence byteSequence, int offset,
int length) {
return decode(CharsetUtil.UTF_8 //修改此处默认编码
, byteSequence, offset, length);
}

这种方法不好的点就是冗余了一份开源代码到自己项目中,并且项目包路径会比较奇怪。当然也可以编译一份修改后的代码放到自己公司的nexus库中。

解决resteasy上传表单文件名乱码的更多相关文章

  1. 【Flask】 结合wtforms的文件上传表单

    表单中的文件上传 基本的表单渲染,表单类设置等等就不多说了,参看另一个文章即可.但是那篇文章里没有提到对于FileField,也就是上传文件的表单字段是如何处理,后端又是如何实现接受上传过来的文件的. ...

  2. ajax上传表单的俩种方式

    1.用h5对象上传表单(图片) var formData = new FormData(); formData.append("authenticity_token", '1212 ...

  3. 上传漏洞科普[1]-文件上传表单是Web安全主要威胁

    为了让最终用户将文件上传到您的网站,就像是给危及您的服务器的恶意用户打开了另一扇门.即便如此,在今天的现代互联网的Web应用程序,它是一种 常见的要求,因为它有助于提高您的业务效率.在Facebook ...

  4. bootstrap上传表单的时候上传的数据默认是0 一定要小心

    bootstrap上传表单的时候上传的数据默认是0 一定要小心

  5. php上传中文文件文件名乱码问题

    php上传文件是最最基础的一个技术点,但是深入进去也有不少问题需要解决,这不,上传中文文件后,文件名变成了乱码. 下面是问题代码,很简单: 1.问题代码 html部分: <html> &l ...

  6. php上传文件中文文件名乱码的解决方法

    文件上传是我们在处理表单提交时候最常用的功能之一,今天写了一个小小的demo,如下: 先看结构: html为表单提交的页面,php为处理表单的文件,upload为上传文件所放的位置 html: < ...

  7. 解决swfupload上传控件文件名中文乱码问题 三种方法 flash及最新版本11.8.800.168

    目前比较流行的是使用SWFUpload控件,这个控件的详细介绍可以参见官网http://demo.swfupload.org/v220/index.htm 在使用这个控件批量上传文件时发现中文文件名都 ...

  8. 使用ajax上传表单(带文件)

    在使用form表单的时候上传文件+表单,会使得页面跳转,而在某些时候不希望跳转,只变化页面中的局部信息 通过查找资料,可以使用FormData进行ajax操作. FormData介绍:XMLHttpR ...

  9. 原生js封装ajax:传json,str,excel文件上传表单提交

    由于项目中需要在提交ajax前设置header信息,jquery的ajax实现不了,我们自己封装几个常用的ajax方法. jQuery的ajax普通封装 var ajaxFn = function(u ...

随机推荐

  1. CRC16算法之一:CRC16-CCITT-FALSE算法的java实现

    CRC16算法系列文章: CRC16算法之一:CRC16-CCITT-FALSE算法的java实现 CRC16算法之二:CRC16-CCITT-XMODEM算法的java实现 CRC16算法之三:CR ...

  2. BZOJ2006:[NOI2010]超级钢琴

    浅谈\(RMQ\):https://www.cnblogs.com/AKMer/p/10128219.html 题目传送门:https://www.lydsy.com/JudgeOnline/prob ...

  3. C# Unit Test 备注

    1. UT工程的编译一定要让依赖的dll在同一目录,即和测试目标dll运行的环境一样. 比如 Demo-UT测试Demo工程, 则Demo工程依赖的所有dll必须和Demo输出的可执行环境Demo.d ...

  4. grep的用法(CentOS7)及有关正则表达式的使用

    环境准备:alias grep="grep --color" 1.grep以整行为单位进行处理,行中有的匹配显示出来 Last中取出符合root的行:grep  '查找字符串' l ...

  5. CodeForces 484A Bits(水题)

    A. Bits time limit per test 1 second memory limit per test 256 megabytes input standard input output ...

  6. ASP.NET学习笔记(四)CDOSYS邮件

    使用 CDOSYS 发送电子邮件 CDO (Collaboration Data Objects) 是一项微软的技术,设计目的是用来简化通信程序的创建. CDOSYS 是 ASP 中的内置组件.我们会 ...

  7. Golang : pflag 包简介

    笔者在前文中介绍了 Golang 标准库中 flag 包的用法,事实上有一个第三方的命令行参数解析包 pflag 比 flag 包使用的更为广泛.pflag 包的设计目的就是替代标准库中的 flag ...

  8. ajax异步传输数据,return返回值为空

    今天在项目中遇到了一个问题,就是在定义了一个函数drawHtml(),本意是想在函数运行结束后,返回拼接的字符串,可是函数运行结束后始终返回的是undefined 有BIG的代码: function ...

  9. nginx 反向代理配置 upstream

    最近项目要写后台,用nodejs写服务接口,然后研究了下nginx反向代理,各种坑下来,也总算把代理配了下来. 我本地用nodejs起了两个服务,一个端口是8888,一个端口是8889,在启动ngin ...

  10. springCloud学习总览

      写完最后一篇特意去看了看第一篇是什么时候写的---2018/11/19,到现在三个月多一点,总的来说这三个月通过<Spring 微服务实战>这本书,算是对微服务进行了一次扫盲学习.   ...