http传参的改进思路

后台语言Java, 基于Servlet规范

前端语言js

1. 普通参数

Map map = request.getParameterMap(); 返回值类型为 Map<String,String[]>
http规范本身可以传递多个相同name的键值
如: $protocol://$ip:$port?name=zhang&name=tian&name=xiao

这个map, key就是表单控件的name, 但value却是一个数组, 而非字符串
而我所知道的, 见过的 xhr请求代码, 更多的是传递json对象, value肯定是个字符串,
不曾考虑value为数组的场景, 可能是因为在过去很长的时间内mysql都不支持数组类型?
间接导致了使用Mysql的程序员也不考虑使用数组类型, 要知道 json不是类型规范, 但数组是

下边我将用js原生代码收集一个form表单内所有的键值

html:

<form>
    <input type="text" name="a" value="1">
    <input type="password" name="b" value="2">

    <input type="hidden" name="c" value="1">

    <input type="hidden" name="d" value="1">
    <input type="hidden" name="d" value="2">

    <input type="radio" name="e" value="1" checked>
    <input type="radio" name="e" value="2">
    <input type="radio" name="e" value="3">


    <input type="checkbox" name="f" value="1" checked>
    <input type="checkbox" name="f" value="2">
    <input type="checkbox" name="f" value="3">

    <select name="g">
        <option value="1">1</option>
        <option value="2">2</option>
        <option value="3">3</option>
    </select>

    <select name="h" multiple>
        <option value="1" selected>1</option>
        <option value="2" selected>2</option>
        <option value="3">3</option>
    </select>

    <textarea name="i" cols="30" rows="10">i</textarea>

    <br>
    <button id="btn" type="button">查看参数</button>
</form>

javascript:

/*
 有的表单控件 提交时若值为''则不传递, 添加 if_empty_not_transfer 属性即可 
* */
    document.getElementById("btn").addEventListener('click', function () {
        getFormDataV1(document.querySelector('form'))
    })

    function getFormDataV1(form_element) {
        var elements = form_element.elements;

        // set , es6的东东, 会有兼容性问题
        var names = new Set();
        // 先获取表单内所有表单元素的name值

        for (var o of elements) {
            names.add(o.name)
        }

        var kvs = {};

        for (var name of names) {
            // name为空则跳过
            if (name === '') continue;


            var element = elements[name];
            // console.log(elements[name])

            // 单个的 input控件, 文本框, 密码框, radio, checkbox
            if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement) {
                let value = element.value;
                //value 为空字符串, 且存在 if_empty_not_transfer 属性, 不传输
                if (value === '' && element.getAttribute('if_empty_not_transfer') != null) {

                } else {
                    kvs[name] = value;
                }

            }
            // 多个同名radio 或 同名checkbox 或 同名input[type="hidden"] 或同名textarea 
            else if (element instanceof RadioNodeList) {
                //  console.log(element)
                var arr = [];
                for (var x of element) {
                    // 单选
                    if (x.type === 'radio') {
                        // 选中
                        if (x.checked) {
                            kvs[name] = x.value;
                            // return
                            break;
                        }
                    }
                    //
                    else if (x.type === 'checkbox') {
                        if (x.checked) {
                            //value 为空字符串, 且存在 if_empty_not_transfer 属性, 不传输
                            if (x.value === '' && x.getAttribute('if_empty_not_transfer') != null) {

                            } else {
                                arr.push(x.value)
                            }
                        }

                    } else {
                        //value 为空字符串, 且存在 if_empty_not_transfer 属性, 不传输
                        if (x.value === '' && x.getAttribute('if_empty_not_transfer') != null) {

                        } else {
                            arr.push(x.value)
                        }
                    }
                }

                // 若在单选且选中那一步已赋值, 这里不再赋值
                if (kvs[name]) {

                } else {
                    kvs[name] = arr;
                }
            }
            // select 标签
            else if (element instanceof HTMLSelectElement) {
                // console.log(element)
                if (element.multiple) {
                    kvs[name] = [];
                    for (let opt of element.selectedOptions) {
                        kvs[name].push(opt.value)
                    }
                } else {
                    kvs[name] = element.value
                }
            }
        }
        console.log(JSON.stringify(kvs, '  ', '  '))
        return kvs;
    }

结果

{
  "a": "1",
  "b": "2",
  "c": "1",
  "d": [
    "1",
    "2"
  ],
  "e": "1",
  "f": [
    "1"
  ],
  "g": "1",
  "h": [
    "1",
    "2"
  ],
  "i": "i"
}

2. 发送Ajax请求

http请求必要的method只有三种, get, post 和 option
get传输小体积数据, 反之用post
option仅在跨域时作为试探性请求, 由浏览器发出

关于浏览器ajax的对象和方法, 如XMLHttpRequest 或 Fetch, 这里不细说, 我们需要关心的东西越少越好,
关于兼容性, 请求进度, 超时处理等, 会有jquery.ajax 或 axios 替我们封装并提供更加人性化的方法

我们还需要做的就是把上一小节中结果的json对象, 转换为 get url, 或 post FormData, 然后交由 jquery.ajax 或 axios

3. 上传文件

我个人非常不建议将其他参数文件上传放在同一个请求当中, post请求, 想要获取其他参数, 就必须解析完整的http请求, 包括文件数据,
当需要对其他参数进行校验, 这段时间文件数据会白白占用内存

posted @ 2019-02-24 11:22  张天笑  阅读(451)  评论(0编辑  收藏  举报