手写请求转发模块遇到的问题汇总

背景:
由于一些网络上面的原因,不能使用nginx,需要自己手动转发请求,涉及HttpServlet中的请求构造以及转发
请求类型:GET,POST
参数类型:json,form
业务:正常业务访问.上传下载,图片查看
其中有趟到以下坑,记录一下,为后来者做一点参考

1.HttpServletResponse设置Content-Type未生效

场景:
在HttpUtil请求获取返回值后,设置返回的contentType,因为通用工具,告诉前端浏览器使用对应的解析器来解析返回值,代码如下

    private void dealResponse(HttpServletResponse resp, byte[] data, String contentType) {
        resp.setHeader(Constant.CONTENT_TYPE[0], contentType);
//        resp.setContentType(contentType);
        try (ServletOutputStream out = resp.getOutputStream()) {
            if (out != null) {//在关资源前一定要判断是否为空
//              IOUtils.write(data, out);
                out.write(data);
                out.flush();
                out.close();
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

问题分析:
参考以下文章,认为HttpServlet设置contentType无效,于是自己定义Controller,使用无返回值方法来解析上面dealResponse的返回值,但结果contentType还是没有生效,后面把data打印出来,参数如下字符串,这居然是字符串,HttpServlet在判断返回值为字符串时,不会再调用contentType设置.所以导致一直没有生效.
最后返回正确的json格式后,在HttpServlet设置contentType是有效的

new String(data) = "{\"msg\":\"\",\"code\":200,\"data\":[{\"createdBy\":null,\"lastUpdatedBy\":null,\"creationDate\":\"2021-10-18 19:22:40\",\"lastUpdateTime\":\"2021-10-18 19:22:40\",\"activeFlag\":null,\"id\":\"f8370a5eafac4c8b929e40090136051c\"}],\"success\":true}"

有以下文章参考
[Bug] HttpServletResponse设置Content-Type未生效

2.从HttpServlet中获取不到附件信息

获取不到任何附件信息,按照StandardMultipartHttpServletRequest中的Collection parts = request.getParts()可以获取到附件,但是获取不到附件之外的参数,所以再继续找,如以下将HttpServletRequest 装换为MultipartHttpServletRequest可以获取到付件并且获取到附件之外的参数

protected ServletRequestVO buildUploadParam(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        log.info(">>>>>>>>>>doUpload()<<<<<<<<<<<");
        ServletRequestVO servletRequestVO = new ServletRequestVO(req);
        String requestURL = ServersConfig.smrApi + req.getRequestURI();
        CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver(req.getSession().getServletContext());
        MultipartHttpServletRequest multipartRequest = commonsMultipartResolver.resolveMultipart(req);
        List<MultipartFile> multipartFiles = multipartRequest.getFiles("myFiles");
        CustomMultipartFile[] mockMultipartFiles = new CustomMultipartFile[multipartFiles.size()];
        for (int i=0; i< multipartFiles.size(); i++) {
            MultipartFile multipartFile =  multipartFiles.get(i);
            CustomMultipartFile mockMultipartFile = new CustomMultipartFile(ContentType.APPLICATION_OCTET_STREAM.toString(), multipartFile.getOriginalFilename(), multipartFile.getContentType(),multipartFile.getBytes());
            mockMultipartFiles[i] = mockMultipartFile;
        }
       Map<String, Object>  bodyParamMap = new HashMap<>();
        Enumeration<String> paramIte = multipartRequest.getParameterNames();
        while (paramIte.hasMoreElements()) {
            String key = paramIte.nextElement();
            bodyParamMap.put(key, multipartRequest.getParameter(key));
        }
        log.info("bodyParamMap : {}", JSON.toJSONString(bodyParamMap));

        Map<String, String> headMap = new HashMap<>();
        headMap.put(Constant.CONTENT_TYPE[0], servletRequestVO.getContentType());
        servletRequestVO.setFiles(mockMultipartFiles);
        servletRequestVO.setBodyParam(JSON.toJSONString(bodyParamMap));
        return servletRequestVO;
}

3.从HttpServlet中获取附件使用MultipartFile[]流传到另外一个模块,反序列化后,没有图片信息,以及图片信息之外的其他参数

MockMultipartFile[] mockMultipartFiles = new MockMultipartFile[multipartFiles.size()];

MultipartFile为接口,fastjson不能序列化接口参数,需要换成MultipartFile的实现类类实现文件的传输以及反序列化,pom引入如下

    <!-- file upload part -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.3.6</version>
    <scope>compile</scope>
</dependency>

4.使用MockMultipartFile[]传到另外一个模块,反序列化后,没有图片信息,以及图片信息之外的其他参数

打印参数,有bytes参数,但是就是没有序列化到MockMultipartFile中,MockMultipartFile[0].isEmpty() = true,说明附件就为空
在这里插入图片描述
问题分析:
打印参数如上,发现有bytes参数传过来,说明序列化没有问题,反序列化出问题了,遂找MockMultipartFile实现,报货content字段在内的字段都为final修饰,所以肯定值没有setxxx方法的,
同时注意下面的getBytes()方法,就明白了序列化的bytes是从哪来的,但是MockMultipartFile字段中没有bytes属性,所以反序列化反射找不到字段,自然不会赋值.
在这里插入图片描述
解决方案:
一种是自定义类继承MockMultipartFile,增加setContent()方法,但是因为是final修饰的,所以此路不通
另外一种就是新增getContent()方法,有content属性,饭序列化反射肯定可以成功赋值,在CustomMultipartFile序列化和反序列化即可

 CustomMultipartFile[] mockMultipartFiles = new CustomMultipartFile[multipartFiles.size()];
public final class CustomMultipartFile extends MockMultipartFile {

    public CustomMultipartFile(String name, String originalFilename, String contentType, byte[] content) {
        super(name, originalFilename, contentType, content);
    }

    public byte[] getContent() throws IOException {
        return super.getBytes();
    }

    public byte[] getBytes() throws IOException {
        return null;
    }

}

4.上传报错UnsupportedOperationException

java.lang.UnsupportedOperationException: Multipart form entity does not implement #getContent()

使用如下方式获取:

HttpEntity httpEntity = entityBuilder.build();
ByteArrayOutputStream out = new ByteArrayOutputStream();
// write content to stream
httpEntity.writeTo(out);
String bodyParam = out.toString();

4.上传报错MultipartException

org.springframework.web.multipart.MultipartException: Current request is not a multipart request

头中设置Content-Type

headMap.put("Content-Type", "multipart/form-data");

4.上传报错FileUploadException

org.apache.tomcat.util.http.fileupload.FileUploadException: the request was rejected because no multipart boundary was found

在第五步设置头的过程中没有设置boundary导致的,而boundary为两个参数二进制的识别标志位,所以毕传,在创建entityBuilder后即创建boundary

MultipartEntityBuilder entityBuilder =  MultipartEntityBuilder.create();
entityBuilder.setCharset(StandardCharsets.UTF_8);
entityBuilder.setBoundary(boundary);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值