后端要求前端传的查询参数 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
zycojamie
V2EX    程序员

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

  •  
  •   zycojamie 2020-04-17 14:39:12 +08:00 via Android 8513 次点击
    这是一个创建于 2001 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    这种方案可行吗。。。

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

    关注一下防注入就行

    不过虽然是可行, 方案不合理啊, 前端关心的是"模糊查询"而不是"模糊查询用 like"
    BreezeInWind
        6
    BreezeInWind  
       2020-04-17 14:49:29 +08:00
    传一串字符串,如果本身其实是可以精确匹配到的,但是查询人以为是模糊匹配的,因而传的是 like,后端怎么处理呢?一串非常长的数字,本来应该是字符串形式存放的,查询人以为是数字,传的是 int,此时又该怎么处理呢
    jatesun
        7/span>
    jatesun  
       2020-04-17 14:50:35 +08:00
    算了,这种事前端就别揽了
    zycojamie
        8
    zycojamie  
    OP
       2020-04-17 14:51:29 +08:00 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 )

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

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


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

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

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

    有好事者试着传了个 DROP TABLE xxx,然后就没有然后了
    zycojamie
        29
    zycojamie  
    OP
       2020-04-17 15:40:59 +08:00 via Android
    安全的话,后端说他们通过框架层去校验和拦截,前端需要把传统的查询参数由{ user:"张三"}变成{ user:{
    matchType:"1",
    propertyName:"user",
    propertyValue:"张三",
    dataType:"string"
    }}
    matchType 为 1 代表“包含”
    Erroad
        30
    Erroad  
       2020-04-17 15:51:44 +08:00
    前端把 ui“翻译”成参数还是很正常的,拼 sql 是肯定不行的,让前端拼 sql 给后端的后端都是 xx
    U7Q5tLAex2FI0o0g
        31
    U7Q5tLAex2FI0o0g  
       2020-04-17 15:54:12 +08:00
    @cedoo22 #26
    @z1154505909 #27
    你们到底有没看仔细看楼主说的。。。。。。。。。。。。。。无力吐槽
    wyz123723
        32
    wyz123723  
       2020-04-17 15:57:23 +08:00
    现在后端真是越来越烂 /懒了
    wellsc
        33
    wellsc  
       2020-04-17 16:00:49 +08:00
    graphql + 1
    1et
        34
    1et  
       2020-04-17 16:03:14 +08:00
    string 和 int 确实有点迷,传 like 、=没什么问题,比如 name:3 默认等值查询,name_like:3 是模糊查询
    javapythongo
        35
    javapythongo  
       2020-04-17 16:10:51 +08:00
    我觉得可以
    buffzty
        36
    buffzty  
       2020-04-17 16:13:50 +08:00
    我就是这样做的.已经用了一年多了.如果项目很小,开发速度第一可以试试.缺点就是只能普通查询,如果查询有 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  
       2020-04-17 16:14:56 +08:00
    谁能告诉我这破站到底怎么发代码?
    baiyi
        38
    baiyi  
       2020-04-17 16:19:57 +08:00
    GraphQL +10086
    6IbA2bj5ip3tK49j
        39
    6IbA2bj5ip3tK49j  
       2020-04-17 16:40:17 +08:00 via iPhone
    这不就是那个男人经常推广的场景吗?
    masker
        40
    masker  
       2020-04-17 17:00:09 +08:00 via Android
    @pap3r 你这种优越,真把自己当回事
    vitoliu
        41
    vitoliu  
       2020-04-17 17:59:53 +08:00
    防 sql 注入的工具很多,后端随便引一下就解决了,而且的确能摆脱大量的判空和 if else 。
    参数混淆啥的也都没做,而且看参数名应该是 B 端系统吧,用户量少这么干的确也没啥问题。
    不过前端传驼峰不传下划线的确让我感觉挺不得劲的哈哈哈。
    areless
        42
    areless  
       2020-04-17 18:06:44 +08:00 via Android
    可行,写了一套这样的前后端,本来想用。感觉那就每天没事干,盯着前端写 SQL 就可以了
    IGJacklove
        43
    IGJacklove  
       2020-04-17 18:09:47 +08:00
    @ZSeptember 感觉一个接口和这个也没啥关系吧,换个方式,加个枚举什么的都比前端传 like 强吧
    Deffi
        44
    Deffi  
       2020-04-17 18:18:31 +08:00   1
    我是移动端,要是考虑版本迭代,逻辑变更,我不会用这种接口。前端应该尽量少做逻辑处理
    red2dog
        45
    red2dog  
       2020-04-17 18:19:44 +08:00
    graphql ++
    guyeu
        46
    guyeu  
       2020-04-17 18:51:11 +08:00
    在有很多复杂查询的场景使用自己的 DSL 代替若干个接口是有意义的,但需要注意的是不应该让前端拼 SQL,而且需要对 DSL 的应用范围进行限制,最好是从设计上避免危险操作的可能性。
    guyeu
        47
    guyeu  
       2020-04-17 18:52:53 +08:00
    不拼 SQL 的主要原因是让数据库和客户端解耦,因为在不通的架构模式下 SQL 的写法可能有较大差异,这不应该影响客户端实现,而表结构也不应该对客户端透明。
    k9990009
        48
    k9990009  
       2020-04-17 18:59:05 +08:00 via Android
    可以的,但是不要前端拼 SQL 。以前我们前端人手不够,前端也是后端写的。自定义参数解析。然后后端调用根据关键字,这个关键字正好是 mybatis plus 的方法名,通过反射调用自动拼。后端只要继承默认实现 CRUD 就好了。比如前端传 name_leftlike,只要写前端就好了,超爽。后端做参数过滤就好了。
    oatw
        49
    oatw  
       2020-04-17 19:01:40 +08:00 via iPhone
    @zycojamie 不考虑后端的前端和不考虑前端的后端,都是业余选手。就像这个架构师。
    randyo
        50
    randyo  
       2020-04-17 19:05:34 +08:00 via Android
    流量不要钱吗,前端为了摆脱复杂数据果断抛回去让后端自己写
    rioshikelong121
        51
    rioshikelong121  
       2020-04-17 19:08:09 +08:00
    这样前端也得懂表结构了 而且复杂的 sql 怎么处理。还得单独写接口吧。
    kohos
        52
    kohos  
       2020-04-17 19:18:51 +08:00 via Android
    这种如果是 where 后面全部靠前端提供的参数生成的话,很不安全,例如楼主的接口,改一下 roleId 就能操作其他角色的数据了,后端想偷懒也不是这样做的
    component
        53
    component  
       2020-04-17 19:47:46 +08:00
    GraphQL 了解一下
    jugelizi
        54
    jugelizi  
       2020-04-17 19:50:53 +08:00 via iPhone
    可行
    但不是拼接。
    应该是传 json k v 指定查询类型 以及查询内容
    MilletChili
        55
    MilletChili  
       2020-04-17 19:51:20 +08:00
    一般的查询,我都是叫前端去拼的,虽然我就是那个前端
    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  
       2020-04-17 19:56:17 +08:00
    wushigejiajia01
        57
    wushigejiajia01  
       2020-04-17 20:19:01 +08:00 via Android
    楼主大致意思: 前端传参,要把参数类型,以及查询范围都传给后端,这样后端能把接口做的很灵活多用

    应该是这个意思吧?

    只要不是由前端拼接 SQL,这没啥问题啊
    shadeofgod
        58
    shadeofgod  
       2020-04-17 21:30:25 +08:00
    这届后端还是不行
    jswh
        59
    jswh  
       2020-04-17 21:44:49 +08:00
    管理后台可以,产品中最好不要。这事我也干过,本质上可所谓的 restful 或者 graphql 的想法是一样的,就是定义一套自己的 DSL 免得老是做相同的事情。
    lizhuoli
        60
    lizhuoli  
       2020-04-17 21:53:46 +08:00 via iPhone
    重新自己实现一个垃圾版本 GraphQL ?意义何在
    hooopo
        61
    hooopo  
       2020-04-17 21:56:44 +08:00 via Android
    graphql 了解一下
    puilu
        62
    puilu  
       2020-04-18 00:19:07 +08:00
    这届后端不行
    hq136234303
        63
    hq136234303  
       2020-04-18 00:19:35 +08:00
    @zycojamie 你们架构师真的可爱。如果是前端加密做的话 终有一天解开 sql 注入 会爽的飞起的。。。。
    a1562619919
        64
    a1562619919  
       2020-04-18 02:42:38 +08:00 via Android
    数据量极小的模糊查询前端做,比如手机登录帐号。但数据多到超过几十个了明显前端不该处理,或者涉及业务的数据尽量不让前端处理,前端可以模糊查询一下个人非业务的缓存数据(个人姓名手机号这种)
    icy37785
        65
    icy37785  
       2020-04-18 03:15:25 +08:00
    GraphQL + 10086
    bllue
        66
    bllue  
       2020-04-18 05:43:48 +08:00
    架构师应该拎得清
    只要避免前端拼接后端拿来直接用的情况
    Jrue0011
        67
    Jrue0011  
       2020-04-18 06:56:02 +08:00
    @zycojamie 这种设计感觉和 DSL 有点像,elastic search 的查询 api 就是类似的设计
    yufeng0681
        68
    yufeng0681  
       2020-04-18 08:11:26 +08:00
    我能想到 前端能拒绝的理由:
    如果有三个终端 需要使用这个功能。 三个终端的开发都要懂 SQL,都要完整测试,不合理,也浪费成本。
    SyncWorld
        69
    SyncWorld  
       2020-04-18 08:41:53 +08:00
    直接传 SQL 岂不是美包包~
    qce7
        70
    qce7  
       2020-04-18 08:59:21 +08:00
    我们这边用 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  
       2020-04-18 09:48:36 +08:00
    graphql 吧,sql 不安全不太好
    michaelcheng
        72
    michaelcheng  
       2020-04-18 09:53:11 +08:00
    复杂的查询传参还是可以的,不一定是要 sql ,语义化的传参,约定参数类型、运算符、值约束等
    a852695
        73
    a852695  
       2020-04-18 09:59:56 +08:00
    如果是直接传 sql 不可,但是玩着玩着就变成了直接传 sql,不信试试看?后端尝到了甜头。
    如果是拼约定字符串可以,玩着玩着,自己都不知道约定了啥。
    onfuns
        74
    onfuns  
       2020-04-18 10:16:11 +08:00
    可行,不过这种方案都是用在内网的系统,可以减少很多的工作量。外网的应用还是应该规规矩矩的,现在的安全可是很敏感了。
    royzxq
        75
    royzxq  
       2020-04-18 12:58:07 +08:00
    这不就是传说中 apiJSON 的场景吗, 让你们后端用啊(
    pap3r
        76
    pap3r  
       2020-04-20 13:12:53 +08:00
    @masker 后端儿子连数据类型都要前端传 怎么优越了? 你就是后端儿子吧
    masker
        77
    masker  
       2020-04-20 13:35:07 +08:00 via Android
    @pap3r 说实话挺可怜你们这种伪物理阉割的太监的呀。。。自己生育功能不行,还喜欢到处叫别人儿子。。
    pap3r
        78
    pap3r  
       2020-05-16 00:16:08 +08:00
    @masker 说实话没父母的孤儿 有人叫你声儿子 你就认了吧
    pap3r
        79
    pap3r  
       2020-05-16 00:18:42 +08:00
    @masker 自动抬杠怪物 人身攻击 好恶心 生活肯定过得很凄惨
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5818 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 30ms UTC 02:43 PVG 10:43 LAX 19:43 JFK 22:43
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86