• 请不要在回答技术问题时复制粘贴 AI 生成的内容
ZeIda
V2EX  ›  程序员

后端要求前端传的查询参数

  •  
  •   ZeIda · Apr 17, 2020 via Android · 9114 views
    This topic created in 2240 days ago, the information mentioned may be changed or developed.

    比如,你输入一个手机号,进行查询,要把你手机号的值,查询是 like 还是=,数据是 string 还是 int,模糊还是精准查询,全部前端拼给后端。。。

    这种方案可行吗。。。

    79 replies    2020-05-16 00:18:42 +08:00
    onepunch
        1
    onepunch  
       Apr 17, 2020
    模糊查询前端做
    racecoder00
        2
    racecoder00  
       Apr 17, 2020   ❤️ 1
    不怕前端传个 drop table?
    dremy
        3
    dremy  
       Apr 17, 2020 via iPhone
    SQL 注入了解一下,公司分分钟倒闭
    opengps
        4
    opengps  
       Apr 17, 2020
    关键词,和是否 like,可以传
    至于 string 还是 int 啥意思?
    Jooooooooo
        5
    Jooooooooo  
       Apr 17, 2020
    可行

    关注一下防注入就行

    不过虽然是可行, 方案不合理啊, 前端关心的是"模糊查询"而不是"模糊查询用 like"
    BreezeInWind
        6
    BreezeInWind  
       Apr 17, 2020
    传一串字符串,如果本身其实是可以精确匹配到的,但是查询人以为是模糊匹配的,因而传的是 like,后端怎么处理呢?一串非常长的数字,本来应该是字符串形式存放的,查询人以为是数字,传的是 int,此时又该怎么处理呢
    jatesun
        7
    jatesun  
       Apr 17, 2020
    算了,这种事前端就别揽了
    ZeIda
        8
    ZeIda  
    OP
       Apr 17, 2020 via Android
    [' tempMatchType ": " 5,4 ", " propertyName ": " name,mobile, " propertyvaluel ": ",13541218876 "),
    {" tempMatchType ": " 7 ", " propertyName ": " age " " propertyvaluel ": " 12 ", " tempType ": " Integer "},
    tempMatchType ": " 11 ", " propertyName ": " role.id ", " prepertyvalue1 ": " 1,2,3,4 ", " tempType ": " List < Long >"}]
    翻译成 hql = where ( name like %张三%' or mobile = 13541218876 and age > 12 and role.idin ( 1.2.3.4 )

    前端就要把查询参数封装成上面那种数组
    ZeIda
        9
    ZeIda  
    OP
       Apr 17, 2020 via Android
    @jatesun 后端架构师说,为了他们拜托大量 if else,所以要求前端按照他们订的查询规则封装请求参数。。。
    U7Q5tLAex2FI0o0g
        10
    U7Q5tLAex2FI0o0g  
       Apr 17, 2020
    我觉得楼主的意思并不是说前端要拼接好 ‘mobile like '%123%'’这样提交给后端,而是使用
    {'field': 'mobile', 'value': '123', 'is_fuzzy': true} 这样传给后端,让后端去拼接。
    loading
        11
    loading  
       Apr 17, 2020 via Android
    先在手机号前后拼接%,然后参数查询,用 like 。

    如果有注入风险,请大佬们马上提醒我。
    loading
        12
    loading  
       Apr 17, 2020 via Android
    sql 参数拼接还是不难的,没几行。
    谁都是 crud boy 。
    ZeIda
        13
    ZeIda  
    OP
       Apr 17, 2020 via Android
    @littleylv 类似,但要求更复杂些(把大于等于,小于,小于等于,等于)都约定好是什么特定值,然后前端传参的时候,就要传(大于等于,小于,小于等于,等于)
    U7Q5tLAex2FI0o0g
        14
    U7Q5tLAex2FI0o0g  
       Apr 17, 2020
    @loading #11
    @loading #12 没看懂你想表达什么


    @zycojamie #13 我觉得这么做挺好的,没问题
    Rwing
        15
    Rwing  
       Apr 17, 2020
    GraphQL 欢迎你
    yukiloh
        16
    yukiloh  
       Apr 17, 2020 via Android   ❤️ 2
    这种接口别被我逮到,不然就直接送你出名
    looplj
        17
    looplj  
       Apr 17, 2020
    这不是很正常的吗,难道不同的查询就要新增加一个接口?
    RESTful 一般只提供一个查询接口,参考
    https://github.com/Microsoft/api-guidelines/blob/master/Guidelines.md#971-filter-operations
    lancerly
        18
    lancerly  
       Apr 17, 2020
    @zycojamie 这太搞笑了吧,前端的代码就不需要整洁性了?就可以随便写一大堆 if else 了?
    wangxiaoaer
        19
    wangxiaoaer  
       Apr 17, 2020
    @yukiloh #16 这种接口有什么问题吗?

    假如一些业务系统就是很需要很精确的查询:比较、类别、模糊 /精确切换等你怎么做???

    现在后端要求是前端把这些非常精细的条件传过去,后端翻译成 sql,又没让前端直接拼、传 sql,只要后端在生成 sql 的时候做好防注入,有什么问题?
    pap3r
        20
    pap3r  
       Apr 17, 2020
    前端爸爸不帮后端儿子擦屁股
    jziwenchen
        21
    jziwenchen  
       Apr 17, 2020
    graphql 可以了解看看
    sun1991
        22
    sun1991  
       Apr 17, 2020
    要区分具体需求是什么再谈实现, 不要一上来就一顿喷...
    曾经做过的灵活可定制查询界面大概就是这样的实现.
    lneoi
        23
    lneoi  
       Apr 17, 2020
    这样处理太繁琐了吧 有点像是做后台的大量查询的需求
    fumichael
        24
    fumichael  
       Apr 17, 2020
    像这个一样?前端可以组装查询条件呀
    但不能后端直接接收前端参数作为 sql 语句
    我想到的是,可以使用枚举进行处理
    https://i.loli.net/2020/04/17/AfIQ4U7weZtDdSB.png
    purensong
        25
    purensong  
       Apr 17, 2020
    graphQL 不错
    dr1q65MfKFKHnJr6
        26
    dr1q65MfKFKHnJr6  
       Apr 17, 2020
    没安全规则吗???让前端拼。。😂😂
    z1154505909
        27
    z1154505909  
       Apr 17, 2020
    前端拼接????头一次听说
    CismonX
        28
    CismonX  
       Apr 17, 2020   ❤️ 1
    突然想起来之前我们学校有个英语课在线答题系统,前端传给后端的参数是一条条完整的 SQL 。

    有好事者试着传了个 DROP TABLE xxx,然后就没有然后了😂
    ZeIda
        29
    ZeIda  
    OP
       Apr 17, 2020 via Android
    安全的话,后端说他们通过框架层去校验和拦截,前端需要把传统的查询参数由{ user:"张三"}变成{ user:{
    matchType:"1",
    propertyName:"user",
    propertyValue:"张三",
    dataType:"string"
    }}
    matchType 为 1 代表“包含”
    Erroad
        30
    Erroad  
       Apr 17, 2020
    前端把 ui“翻译”成参数还是很正常的,拼 sql 是肯定不行的,让前端拼 sql 给后端的后端都是 xx
    U7Q5tLAex2FI0o0g
        31
    U7Q5tLAex2FI0o0g  
       Apr 17, 2020
    @cedoo22 #26
    @z1154505909 #27
    你们到底有没看仔细看楼主说的。。。。。。。。。。。。。。无力吐槽
    wyz123723
        32
    wyz123723  
       Apr 17, 2020
    现在后端真是越来越烂 /懒了
    wellsc
        33
    wellsc  
       Apr 17, 2020
    graphql + 1
    1et
        34
    1et  
       Apr 17, 2020
    string 和 int 确实有点迷,传 like 、=没什么问题,比如 name:3 默认等值查询,name_like:3 是模糊查询
    javapythongo
        35
    javapythongo  
       Apr 17, 2020
    我觉得可以
    buffzty
        36
    buffzty  
       Apr 17, 2020
    我就是这样做的.已经用了一年多了.如果项目很小,开发速度第一可以试试.缺点就是只能普通查询,如果查询有 join 的需要手动写规则
    下面这个是我查询列表的一个通用方法.新加一个模型只需要设置一下 model 类型 和 filter 映射和 order 映射
    用这套接口速度起飞,但有局限性
    ```php
    // Base controller
    public function lists(): Json
    {
    $json = new JsonRes();
    [$page, $limit, $filter, $order, $extra] = $this->getListParam();
    $scene = $extra['scene'] ?? $this->model::SCENE['default'];
    $where = $this->model::buildWhereMap($filter);
    $fmtOrder = $this->model::buildFmtOrder($order);
    if ( $scene === $this->model::SCENE['admin'] && !$this->isAdminUser() ) {
    return $this->noAuth();
    }
    [$list, $count] = $this->model::getListNotThrowEmptyEx($page, $limit,
    $this->model::NEED_COUNT, $where, [], $order);
    $fmtList = [];
    /** @var \app\model\Base $model */
    foreach ($list as $model) {
    $fmtList[] = $model->getFmtDetail($scene);
    }
    $json->setData([
    'list' => $fmtList,
    ]);
    $json->setPage($page);
    $json->setLimit($limit);
    $json->setCount($count);
    return json($json);
    }

    // Base Model
    /**
    * 根据 filter 构建查询条件.
    *
    * @param array|null $filterList
    * @param array $filterFieldMapDbField
    * @return array
    */
    public static function buildWhereMap($filterList, array $filterFieldMapDbField =
    []): array
    {

    $filterFieldMapDbField = empty($filterFieldMapDbField) ? static::FILTER_FIELD_MAP_DB_FIELD : $filterFieldMapDbField;
    $map = [];
    if ( !is_array($filterList) ) {
    return [];
    }
    foreach ($filterList as $filterField => $item) {
    if ( $item instanceof Closure ) {
    $map[] = $item;
    continue;
    }
    if ( !is_array($item) || !array_key_exists('condition', $item)
    || !array_key_exists('val', $item) ) {
    continue;
    }
    if ( $item['val'] === '' || $item['condition'] === Condition::TYPE['undefined'] ||
    !in_array($item['condition'], Condition::TYPE, true)
    ) {
    continue;
    }
    if ( !array_key_exists($filterField, $filterFieldMapDbField) ) {
    continue;
    }
    $dbField = $filterFieldMapDbField[$filterField];
    $condition = Condition::DB_CONDITION[$item['condition']];
    $map[] = [
    $dbField, $condition, Condition::formatVal($item['condition'], $item['val']),
    ];
    }

    return $map;
    }
    ```
    前端代码:
    ```typescript
    // 一个模型只需要定义下面这些 就可以使用通用增删改查 5 个接口了
    type Model = Expert
    const route = '/expert'
    type FilterKeys =
    | 'id'
    | 'ctime'
    | 'expertCode'
    | 'name'
    | 'userName'
    | 'departmentId'
    | 'orgCode'
    | 'orgName'
    | 'provCode'
    | 'cityCode'
    | 'countyCode'
    | 'provName'
    | 'cityName'
    | 'countyName'
    | 'level'
    | 'intro'
    | 'type'
    | 'mobile'
    | 'phone'
    | 'email'
    | 'qq'
    | 'wx'
    | 'remark'
    | 'serviceType'
    type OrderKeys = 'id' | 'ctime'
    type Scene = 'admin' | 'default'
    interface QueryExtra extends BaseExtra<Scene> {}
    type ActGetListParam = GetListParam<FilterKeys, OrderKeys, QueryExtra>
    type AddData = Omit<Model, 'adeptLabelList' | 'department' | 'id'>
    type EditData = AddData & Pick<Model, 'id'>

    export async function lists<T = Model>(data: ActGetListParam) {
    return bpost<{ list: T[] }>({
    url: route + '/list',
    data,
    })
    }
    ```
    buffzty
        37
    buffzty  
       Apr 17, 2020
    谁能告诉我这破站到底怎么发代码?
    FinnBai
        38
    FinnBai  
       Apr 17, 2020
    GraphQL +10086
    6IbA2bj5ip3tK49j
        39
    6IbA2bj5ip3tK49j  
       Apr 17, 2020 via iPhone
    这不就是那个男人经常推广的场景吗?
    masker
        40
    masker  
       Apr 17, 2020 via Android
    @pap3r 你这种优越🐶,真把自己当回事
    vitoliu
        41
    vitoliu  
       Apr 17, 2020
    防 sql 注入的工具很多,后端随便引一下就解决了,而且的确能摆脱大量的判空和 if else 。
    参数混淆啥的也都没做,而且看参数名应该是 B 端系统吧,用户量少这么干的确也没啥问题。
    不过前端传驼峰不传下划线的确让我感觉挺不得劲的哈哈哈。
    areless
        42
    areless  
       Apr 17, 2020 via Android
    可行,写了一套这样的前后端,本来想用。感觉那就每天没事干,盯着前端写 SQL 就可以了
    IGJacklove
        43
    IGJacklove  
       Apr 17, 2020
    @ZSeptember 感觉一个接口和这个也没啥关系吧,换个方式,加个枚举什么的都比前端传 like 强吧
    Deffi
        44
    Deffi  
       Apr 17, 2020   ❤️ 1
    我是移动端,要是考虑版本迭代,逻辑变更,我不会用这种接口。前端应该尽量少做逻辑处理
    red2dog
        45
    red2dog  
       Apr 17, 2020
    graphql ++
    guyeu
        46
    guyeu  
       Apr 17, 2020
    在有很多复杂查询的场景使用自己的 DSL 代替若干个接口是有意义的,但需要注意的是不应该让前端拼 SQL,而且需要对 DSL 的应用范围进行限制,最好是从设计上避免危险操作的可能性。
    guyeu
        47
    guyeu  
       Apr 17, 2020
    不拼 SQL 的主要原因是让数据库和客户端解耦,因为在不通的架构模式下 SQL 的写法可能有较大差异,这不应该影响客户端实现,而表结构也不应该对客户端透明。
    k9990009
        48
    k9990009  
       Apr 17, 2020 via Android
    可以的,但是不要前端拼 SQL 。以前我们前端人手不够,前端也是后端写的。自定义参数解析。然后后端调用根据关键字,这个关键字正好是 mybatis plus 的方法名,通过反射调用自动拼。后端只要继承默认实现 CRUD 就好了。比如前端传 name_leftlike,只要写前端就好了,超爽。后端做参数过滤就好了。
    oatw
        49
    oatw  
       Apr 17, 2020 via iPhone
    @zycojamie 不考虑后端的前端和不考虑前端的后端,都是业余选手。就像这个架构师。
    randyo
        50
    randyo  
       Apr 17, 2020 via Android
    流量不要钱吗,前端为了摆脱复杂数据果断抛回去让后端自己写
    rioshikelong121
        51
    rioshikelong121  
       Apr 17, 2020
    这样前端也得懂表结构了 而且复杂的 sql 怎么处理。还得单独写接口吧。
    kohos
        52
    kohos  
       Apr 17, 2020 via Android
    这种如果是 where 后面全部靠前端提供的参数生成的话,很不安全,例如楼主的接口,改一下 roleId 就能操作其他角色的数据了,后端想偷懒也不是这样做的
    component
        53
    component  
       Apr 17, 2020
    GraphQL 了解一下
    jugelizi
        54
    jugelizi  
       Apr 17, 2020 via iPhone
    可行
    但不是拼接。
    应该是传 json k v 指定查询类型 以及查询内容
    MilletChili
        55
    MilletChili  
       Apr 17, 2020
    一般的查询,我都是叫前端去拼的,虽然我就是那个前端
    start_num = int(request.GET.get('start_num') or 0) # 起始数
    get_num = int(request.GET.get('get_num') or 10) # 需求数
    filters = request.GET.get('filters') # 筛选条件
    sorts = request.GET.get('sorts') # 排序条件
    want_fileds = request.GET.get('want_fileds') # 指定需要的字段
    is_distinct = request.GET.get('is_distinct') # 是否去重

    qset = model.objects.using(using_database).all()

    if filters:
    # print('筛选条件:',filters)
    qset = filterHelper(filters, qset)
    if sorts:
    # print('排序条件:',sorts)
    qset = qset.order_by(*sorts.split(','))
    if is_distinct == 'yes':
    qset = qset.distinct()

    all_num = qset.count() # 总个数
    qset = qset[start_num: start_num + get_num]

    if want_fileds:
    data_list = createSerializers(model, want_fileds.split(','))(qset, many=True).data
    else:
    data_list = Ser_L(qset, many=True).data
    data = {'all_num': all_num, 'data_list': data_list}
    CEBBCAT
        56
    CEBBCAT  
       Apr 17, 2020
    wushigejiajia01
        57
    wushigejiajia01  
       Apr 17, 2020 via Android
    楼主大致意思: 前端传参,要把参数类型,以及查询范围都传给后端,这样后端能把接口做的很灵活多用

    应该是这个意思吧?

    只要不是由前端拼接 SQL,这没啥问题啊
    shadeofgod
        58
    shadeofgod  
       Apr 17, 2020
    这届后端还是不行 🐶
    jswh
        59
    jswh  
       Apr 17, 2020
    管理后台可以,产品中最好不要。这事我也干过,本质上可所谓的 restful 或者 graphql 的想法是一样的,就是定义一套自己的 DSL 免得老是做相同的事情。
    lizhuoli
        60
    lizhuoli  
       Apr 17, 2020 via iPhone
    重新自己实现一个垃圾版本 GraphQL ?意义何在
    hooopo
        61
    hooopo  
       Apr 17, 2020 via Android
    graphql 了解一下
    puilu
        62
    puilu  
       Apr 18, 2020
    这届后端不行
    hq136234303
        63
    hq136234303  
       Apr 18, 2020
    @zycojamie 你们架构师真的可爱。如果是前端加密做的话 终有一天解开 sql 注入 会爽的飞起的。。。。
    a1562619919
        64
    a1562619919  
       Apr 18, 2020 via Android
    数据量极小的模糊查询前端做,比如手机登录帐号。但数据多到超过几十个了明显前端不该处理,或者涉及业务的数据尽量不让前端处理,前端可以模糊查询一下个人非业务的缓存数据(个人姓名手机号这种)
    icy37785
        65
    icy37785  
       Apr 18, 2020
    GraphQL + 10086
    bllue
        66
    bllue  
       Apr 18, 2020
    架构师应该拎得清
    只要避免前端拼接后端拿来直接用的情况
    Jrue0011
        67
    Jrue0011  
       Apr 18, 2020
    @zycojamie 这种设计感觉和 DSL 有点像,elastic search 的查询 api 就是类似的设计
    yufeng0681
        68
    yufeng0681  
       Apr 18, 2020
    我能想到 前端能拒绝的理由:
    如果有三个终端 需要使用这个功能。 三个终端的开发都要懂 SQL,都要完整测试,不合理,也浪费成本。
    SyncWorld
        69
    SyncWorld  
       Apr 18, 2020
    直接传 SQL 岂不是美包包~
    qce7
        70
    qce7  
       Apr 18, 2020
    我们这边用 Yii2 的 DSL


    // 过滤条件
    // 过滤条件按需使用,没有过滤条件就不传 filter
    "filter": {
    // and 表示 "且",也支持 or,但是实际业务用的比较少而且性能不佳 or 不建议使用
    "and": [
    // like 条件
    {"mobile": {"like": "1"}},
    // level = 1
    {"level": 1},
    // 范围条件 id in [2, 5, 9]
    {"id": {"in": [2, 5, 9]}},
    // createdAt > 0
    {"createdAt": {"gt":0}},
    // createdAt < 10000000000
    {"createdAt": {"lt":10000000000}}
    ]
    }
    // 每页记录数,后端默认 10 条
    "perPage": 10,
    // 请求页数
    "page": 1,
    // 排序值,优先级从前到后“-”表示倒序
    "sort": "-isDefault,-isCertified,-id"
    }
    SjwNo1
        71
    SjwNo1  
       Apr 18, 2020
    graphql 吧,sql 不安全不太好
    michaelcheng
        72
    michaelcheng  
       Apr 18, 2020
    复杂的查询传参还是可以的,不一定是要 sql ,语义化的传参,约定参数类型、运算符、值约束等
    a852695
        73
    a852695  
       Apr 18, 2020
    如果是直接传 sql 不可,但是玩着玩着就变成了直接传 sql,不信试试看?后端尝到了甜头。
    如果是拼约定字符串可以,玩着玩着,自己都不知道约定了啥。
    onfuns
        74
    onfuns  
       Apr 18, 2020
    可行,不过这种方案都是用在内网的系统,可以减少很多的工作量。外网的应用还是应该规规矩矩的,现在的安全可是很敏感了。
    royzxq
        75
    royzxq  
       Apr 18, 2020
    这不就是传说中 apiJSON 的场景吗, 让你们后端用啊(
    pap3r
        76
    pap3r  
       Apr 20, 2020
    @masker 后端儿子连数据类型都要前端传 怎么优越了? 你就是后端儿子吧
    masker
        77
    masker  
       Apr 20, 2020 via Android
    @pap3r 说实话挺可怜你们这种伪物理阉割的太监的呀。。。自己生育功能不行,还喜欢到处叫别人儿子。。
    pap3r
        78
    pap3r  
       May 16, 2020
    @masker 说实话没父母的孤儿 有人叫你声儿子 你就认了吧
    pap3r
        79
    pap3r  
       May 16, 2020
    @masker 自动抬杠怪物 人身攻击 好恶心 生活肯定过得很凄惨
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   2498 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 173ms · UTC 15:51 · PVG 23:51 · LAX 08:51 · JFK 11:51
    ♥ Do have faith in what you're doing.