关于form-data和http请求body&网关处理

这篇具有很好参考价值的文章主要介绍了关于form-data和http请求body&网关处理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

关于form-data和http请求body&网关处理

场景

  • 【在http过网关时,修改内容】

  • 在网关过滤器中,监听所有http请求,截获请求,并且修改body中内容。添加一组用户凭证,然后通过网关走向后台服务

  • 使用applicaon/json的请求时,能很好的解决

  • 使用form-data时,body采用下面的 'boundary—'限定边界,加入参数的形式进行传递

  • 后台我都是通过手动编译http协议body转string

  • 以前都不太清楚http具体内容,现在写出来记一下

  • 使用form-data传递文件时,并且添加参数,展示还未解决


form-data 只传参数—httpbody 对应字符串形式

http–请求协议内容:form-data————表单提交,只携带参数的情况

–form-data : key就是namae=“”的内容 ,value内容就是换行下面的那个参数

----------------------------402066259756119690380117
Content-Disposition: form-data; name="userId"

wuhong
----------------------------402066259756119690380117
Content-Disposition: form-data; name="123"

123123
----------------------------402066259756119690380117--

form-data 传文件 —httpbody 对应字符串形式

http–请求协议内容:form-data----携带文件的情况

  • 传文件的boundary边界中,添加了filename的标识
  • 【Content-Type: image/png】能看出文件的类型
    中间的内容是文件的内容
----------------------------360975841684466334428049
Content-Disposition: form-data; name="file"; filename="image-20210224172302222.png"
Content-Type: image/png

�PNG

IHDR  G     OEV>    IDATx��W��H����88:���U�ʪ������Y�,�\.�h���1�4^�xA3��v�8�;Þ���V�EjZG- �y� '"23";�*�
�x�P����u�'~p�	�A����M#��ԍF�M3�X�@���yד!lD�c't�3�V�A��I$� �۱�~�)#*��to�|!B�A���% �
��p`Z���]���U:�{8&
�	��:�\}
�� �(�F#�@����f�v%N7�aHL�
�)���,�K�)R�H�"E�)R���L+_z^"�CDh�,�DDd���PU��M��a���{v���+x�OXI���H�"E�CD��{!�hQ�;m����9�G�D
�#�~��H�h��粯
----------------------------360975841684466334428049--

温馨提示:如果要手动编辑http - form-data的body。如上面的格式,需要自行研究body的换行符号,我之前就是看着图上的格式进行\n换行,结果真实格式有一点点不一样,有点地方还要加斜杠。具体下面的filter代码有

吐槽&结果

  1. gateway处理非常恶心,加了webflux,响应式流的内容。这块方向我还是个彩笔
  2. 最后的代码方案其实能解决form-data传文件时,加入一组自定义的key-value信息。只是我的加入自定义信息的时候,使用了String打开和编辑。估计是这个地方,对文件的编码出现了影响。大致应该可以通过解析编码格式保存文件。

gateway fileter代码文章来源地址https://www.toymoban.com/news/detail-720932.html

package com.wuhong.filter;



import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import com.wuhong.entity.Accounts;
import com.wuhong.utils.JWTUtil;
import io.netty.buffer.ByteBufAllocator;

import lombok.extern.slf4j.Slf4j;



import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.factory.rewrite.CachedBodyOutputMessage;
import org.springframework.cloud.gateway.support.BodyInserterContext;
import org.springframework.cloud.gateway.support.DefaultServerRequest;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;

import org.springframework.core.io.buffer.*;

import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.codec.HttpMessageReader;

import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;

import org.springframework.web.reactive.function.BodyInserter;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerStrategies;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.server.ServerWebExchange;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;


import java.io.*;

import java.util.List;

/**
 * @ClassName DiaryFilter
 * @Description TODO
 * @Author director吴
 * @Date 2022/1/16 21:14
 * @Version 1.0
 **/
@Slf4j
@Configuration
public class DiaryFilter implements GlobalFilter, Ordered {
    

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        //从请求头获取Token
        String token = exchange.getRequest().getHeaders().get("token").get(0);

        if (token != null) {
            boolean status = JWTUtil.checkToken(token);
            //验证解析token
            Accounts info = JWTUtil.checkToken(token) ? JWTUtil.getTokenInfo(token) : null;
            ServerHttpRequest request = exchange.getRequest();
            
            HttpHeaders headers = request.getHeaders();
            MediaType contentType = headers.getContentType();
            long contentLength = headers.getContentLength();

            //判断请求类型
            if (contentLength > 0) {
                if (MediaType.APPLICATION_JSON.equals(contentType) || MediaType.APPLICATION_JSON_UTF8.equals(contentType)) {
                    return readJSONBody(exchange, chain, info);
                }
//                if (MediaType.APPLICATION_FORM_URLENCODED.equals(contentType)) {
//                    return readFormData(exchange, chain,gatewayContext);
//                }
                if (MediaType.MULTIPART_FORM_DATA.getSubtype().equals(contentType.getSubtype())) {
                    return readFormData(exchange, chain,info);
                }
            }

            return chain.filter(exchange);

        } else {

            String value = exchange.getRequest().getPath().value();

            if (value.indexOf("login") != -1) {
                return chain.filter(exchange);
            }

        }
        return null;
    }




    /*
    返回一个ServerHttpRequestDecorator对象。
    这个对象是用来构建一个request请求的适配。因为gateway使用webflux,流节点中(Mono、Flux)当request的数据被读取后,
    就不会在原来的节点存在。通俗来讲"就是拿出来用了,就没了。需要继续往下传递,必须再写一个数据放进去"
     */
    public ServerHttpRequestDecorator buildingServerHttpRequestDecorator(ServerWebExchange exchange,byte[] bytes){
        return new ServerHttpRequestDecorator(exchange.getRequest()) {

            //请求头配置
            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders httpHeaders = new HttpHeaders();
                httpHeaders.putAll(super.getHeaders());
                httpHeaders.setContentLength(bytes.length);
                return httpHeaders;
            }

            //请求体,body数据配置
            @Override
            public Flux<DataBuffer> getBody() {
                Flux<DataBuffer> cachedFlux = Flux.defer(() -> {
                    DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);
                    DataBufferUtils.retain(buffer);
                    return Mono.just(buffer);
                });

                return cachedFlux;
            }
        };
    }



    /**
     * 暂未解决的问题:使用form-data-上传文件时,通过修改http请求体,byte转string修改,再转回byte,除了txt文件意外,其他文件都会损坏
     */
    private Mono<Void> readFormData(ServerWebExchange exchange, GatewayFilterChain chain,Accounts tokenInfo) {

        return DataBufferUtils.join(exchange.getRequest().getBody()).flatMap(dataBuffer -> {
            StringBuilder builder = new StringBuilder();
            byte[] bytes = new byte[dataBuffer.readableByteCount()];
            log.info("dataBuffer数据长度==" + dataBuffer.readableByteCount());
            try {
                //读取-响应式流结构中,http-from-data的请求数据
                dataBuffer.read(bytes);
                String bodyInfo = new String(bytes);
                System.out.println(bodyInfo);

                //判断-from-data的请求内容,是否携带了文件。携带了文件的话 body请求体中,会有filename参数
                if (bodyInfo.contains("filename=")){
                    ServerHttpRequestDecorator decorator = buildingServerHttpRequestDecorator(exchange, bytes);
                    return chain.filter(exchange.mutate().request(decorator).build());
                }

                //插入
                String newBody = insertBodyForFromData(bodyInfo, tokenInfo);

                byte[] overByte = newBody.getBytes();

                ServerHttpRequestDecorator decorator = buildingServerHttpRequestDecorator(exchange, overByte);



                return chain.filter(exchange.mutate().request(decorator).build());

            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        });


    }

    private Mono<Void> readJSONBody(ServerWebExchange exchange, GatewayFilterChain chain, Accounts tokenInfo) {

        // httpserverRequest 转 ServerRequest
        ServerRequest serverRequest = new DefaultServerRequest(exchange);

        Mono<String> modifiedBody = serverRequest.bodyToMono(String.class)
                .flatMap(body -> {//请求中的body数据
                    log.info("'[请求中的body数据]':\n" + body);

                    return Mono.just(insertBodyForJSON(body, tokenInfo));
                });
        BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class);
        HttpHeaders headers = new HttpHeaders();
        headers.putAll(exchange.getRequest().getHeaders());
        headers.remove(HttpHeaders.CONTENT_LENGTH);
        CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, headers);

        return bodyInserter.insert(outputMessage, new BodyInserterContext())
                .then(Mono.defer(() -> {
                    ServerHttpRequestDecorator decorator = new ServerHttpRequestDecorator(
                            exchange.getRequest()) {
                        @Override
                        public HttpHeaders getHeaders() {
                            long contentLength = headers.getContentLength();
                            HttpHeaders httpHeaders = new HttpHeaders();
                            httpHeaders.putAll(super.getHeaders());
                            if (contentLength > 0) {
                                httpHeaders.setContentLength(contentLength);
                            } else {
                                httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
                            }
                            return httpHeaders;
                        }

                        @Override
                        public Flux<DataBuffer> getBody() {
                            return outputMessage.getBody();
                        }
                    };
                    return chain.filter(exchange.mutate().request(decorator).build());
                }));
    }


    private String insertBodyForJSON(String oldBody, Accounts insertUserData) {

        JSONObject jsonObject = JSON.parseObject(oldBody);
        jsonObject.put("userId", insertUserData.getId());
        log.info("[gatway添加用户Id信息] :[id=" + insertUserData.getId() + "]");
        jsonObject.put("userAccount", insertUserData.getAccount());
        log.info("[gatway添加用户账号信息] :[account=" + insertUserData.getAccount() + "]");
        return jsonObject.toJSONString();

    }

    private String insertBodyForFromData(String oldBody, Accounts insertUserData) {
        String boundary = oldBody.split("Content-Disposition: form-data;")[0];
        StringBuilder builder = new StringBuilder();
        log.info("请求格式为form-data");
        //http form-data报文格式,需要添加\r\n
        builder.append(boundary + "Content-Disposition: form-data; name=\"userId\"\r\n" +
                "\r\n" +
                "wuhong\r\n");
//                builder.append(boundary + "Content-Disposition: form-data; name=\"userId\"" +
//                        "\n" +
//                        "\n" +
//                        "wuhong\n");
        builder.append(oldBody);
        log.info("修改以后的数据");
        System.out.println(builder.toString());
        return builder.toString();

    }


    private byte[] insertBodyFromData(DataBuffer dataBuffer) {
        InputStream inputStream = dataBuffer.asInputStream();
        StringBuilder builder = new StringBuilder();
        byte[] bytes = new byte[dataBuffer.readableByteCount()];
        System.out.println("dataBuffer数据长度==" + dataBuffer.readableByteCount());
        try {
            dataBuffer.read(bytes);
            String bodyInfo = new String(bytes);
            System.out.println(bodyInfo);
            String formDataInfo = bodyInfo.split("Content-Disposition: form-data;")[0];
            builder.append(formDataInfo + "Content-Disposition: form-data; name=\"userId\"" +
                    "\n" +
                    "\n" +
                    "wuhong\n");
            builder.append(bodyInfo);
            System.out.println(builder.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
        String newBody = builder.toString();
        byte[] overByte = newBody.getBytes();

        return overByte;
    }


    @Override
    public int getOrder() {
        return 1;
    }


}

到了这里,关于关于form-data和http请求body&网关处理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • python-用form-data形式上传文件请求

    虽然现在基本上都约定俗成的接口都用json形式请求 但是不可避免地 有些接口需要传文件流,此时就需要用form-data形式上传了 for.e: 存在以下接口,通过接口创建海报图 但需要上传缩略图, 此时接口的Content-Type就不能是application/json,而是multipart/form-data; 参数格式也是以表单

    2023年04月08日
    浏览(47)
  • postman上传文件(multipart/form-data请求)

    网页的form表单中,如果存在上传文件的表单,则需要将form标签设置enctype=\\\"multipart/form-data\\\"属性,意思是将Content-Type设置成multipart/form-data。 那么如何使用 postman发送 multipart/form-data请求呢? Content-Type: multipart/form-data; boundary= 表单中的 enctype 属性规定在发送到服务器之前应该如

    2024年02月02日
    浏览(71)
  • java发送form-data请求实现文件上传

    需要请求第三方接口上传文件,该请求类型是form-data请求   注意: 这里的 builder.addPart(\\\"sendfile\\\", new FileBody(file)); , multipartFile 对应form表单的字段名称。 参考:Java发送form-data请求实现文件上传_IceFloe_Rot的博客-CSDN博客

    2024年01月18日
    浏览(63)
  • 理解 HTTP 中的 multipart/form-data

    HTTP 是一种基于请求-响应模型的网络通信协议,主要用于 Web 中客户端和服务器之间通信的数据传输。事实上,如今的互联网就是构建在 HTTP 之上的。基于请求-响应模式的通信方式很简单,客户端向服务器发送请求,服务器处理请求并进行响应。 HTTP 其实并不关心我们想要传

    2024年02月08日
    浏览(51)
  • Okhttp实现参数请求接口用postman的form-data请求接口

    1.看下图,是不是这种访问方式 2.如果是这种访问方式,使用okhttp请求接口是这样的。

    2024年02月04日
    浏览(46)
  • python + request实现multipart/form-data请求上传文件

    1、multipart/form-data介绍         multipart/form-data 是 HTTP 协议中用于上传文件的一种类型。它允许客户端向服务器发送文件以及一些额外的元数据(例如文件名、MIME 类型、图片等)。这种类型的请求不同于普通的application/x-www-form-urlencoded 格式,其中数据是在请求体中进行编

    2024年02月11日
    浏览(40)
  • Java请求调用参数格式为form-data类型的接口

    接口参数使用postman调用如图所示,只能使用form-data格式调用 使用java代码发送http请求实现此种方式的接口调用 特别说明:form的Content-Type属性为编码方式 常用有两种 :application/x-www-form-urlencoded和multipart/form-data,默认为application/x-www-form-urlencoded。 x-www-form-urlencoded :当action为

    2024年02月12日
    浏览(57)
  • post请求设置表单form-data格式的几种方式

    我用默认的post方法发送数据的时候发现后端获取不到数据,然而在network中看到参数是的确传出去的了。而且用postman测试的时候也是可以的,比较了下两个的不同发现是postman使用的是form-data格式,于是用form-data格式再次请求,发现OJBK 这两种格式都是无法使用的:   方法一:

    2024年02月11日
    浏览(68)
  • SpringBoot处理form-data表单接收对象数组

    主要是为了存档,碰到表单传对象数组的情况,一般都是一个表单只能传一个对象,后面经过跟前端的研究和讨论发现居然可以传对象数组,以此作为记录分享。 测试直接使用下标方式请求 直接使用属性下标的方式传递 请求: 示例代码: 结果: java.lang.IllegalStateException:

    2024年02月03日
    浏览(63)
  • JAVA实现postman form-data和raw方式请求数据的代码

    java raw方式 的实现代码如下: Url url = new Url(\\\"\\\"); HttpURLConnection connection = (HttpURLConnection ) url.oepnConnection(); connection.setDoOutput(true); connection.setDoInput(true); connection.setUseCaches(false); connection.setInstanceFollowRedirects(true); connection.setRequestMethod(\\\"POST\\\"); connection.setRequestProperty(\\\"Accept\\\",\\\"application/

    2023年04月08日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包