关注互联网应用及运维技术的个人博客

微信小程序应用开发赛的总结回顾

三十五天

从 5.10 加入组队,到 6.15 结束项目。为期大约35天的开发时长。

三十五天中,从最开始纠结传统后端/云开发,到后来的决定前后端独立开发,再后来,因为各种原因(比如做不到)功能增增减减,直到最后两天的疯狂修BUG写文档。

于我自己而言,这是我第一次参与团体开发的项目,也是第一次写一个真正使用的后端(面向公众开放,而非我个人使用)虽然还是一堆 BUG 和漏洞,而且是仅仅实现了最基本的部分(例如没有任何防御,session过期机制等等);不过至少,后端和SQL能力,从增删改查上升到了稍微复杂一些的增删改查。(卑微.jpg)

也还是因为赶时间和不熟悉的原因,很多地方新增功能 = Ctrl+C Ctrl+V,本来 flask 的各模块就相对独立,而这更导致了 API 的混乱

各种错误

HTTP 错误

除了 200 和 302(图片跳转) 正常之外,还有 404, 405, 500, 502 最常见

1. 404

404 ERROR, Not Found

偶尔见到的几种特殊情况:
1. 传递参数为 -1, 0 等默认值:由于cookie失效,或者非正常顺序进入页面,导致无法读取对应信息,传递了默认值或者缺省值
2. 传递 undefined,异步请求,由于还未获取到数据,该变量可能还处于 undefined 状态,如果这时就先调用了,那么可能会导致发送一个例如 /xxx/api?id=undefined 的请求。

2. 405

405 ERROR, METHOD NOT ALLOWED

127.0.0.1 - - [14/Jun/2020 21:29:47] "POST /usr/unsettag HTTP/1.0" 405 -

采用了不支持的方法(通常是将 GETPOST 传递混了)

3. 500

500 ERROR, INTERNAL SERVER ERROR

服务器内部错误,大多是 flask 程序运行时崩溃,由底层代码抛出异常, flask 捕获后,如果是 GET 并且处于调试模式,则会显示一个异常页面。(包括调用栈、错误信息、调试等等)

4. 502

502 Bad Gateway

flask 在调试模式时,文件更改,会自动重新运行。但是重新运行遇到了语法错误的时候(例如缩进问题等等),会直接发生崩溃。
而程序后端采用了 nginx 反代 + flask 的方式,当反向代理失败的时候,就是 502 Bad Gateway

数据库错误

1. 参数少传递

sql = "insert into `temp` (`val`, `time`) values (%s, %s);"
cur.execute(sql, (2, ))
Traceback (most recent call last):
  File "/usr/Python-3.8.2/lib/python3.8/site-packages/MySQLdb/cursors.py", line 204, in execute
    query = query % args
TypeError: not enough arguments for format string

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "1.py", line 15, in <module>
    cur.execute(sql, (2, ))
  File "/usr/Python-3.8.2/lib/python3.8/site-packages/DBUtils/SteadyDB.py", line 605, in tough_method
    result = method(*args, **kwargs)  # try to execute
  File "/usr/Python-3.8.2/lib/python3.8/site-packages/MySQLdb/cursors.py", line 206, in execute
    raise ProgrammingError(str(m))
MySQLdb._exceptions.ProgrammingError: not enough arguments for format string

重点

TypeError: not enough arguments for format string
MySQLdb._exceptions.ProgrammingError: not enough arguments for format string

参数不足,指定了使用 values (%s, %s); 但是最后传递的 (2, ),仅仅传递了一个参数

2. 参数多传递

sql = "insert into `temp` (`val`, `time`) values (%s, CURRENT_TIMESTAMP());"
cur.execute(sql, (2, 1))
raceback (most recent call last):
  File "/usr/Python-3.8.2/lib/python3.8/site-packages/MySQLdb/cursors.py", line 204, in execute
    query = query % args
TypeError: not all arguments converted during bytes formatting

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "1.py", line 15, in <module>
    cur.execute(sql, (2, 1))
  File "/usr/Python-3.8.2/lib/python3.8/site-packages/DBUtils/SteadyDB.py", line 605, in tough_method
    result = method(*args, **kwargs)  # try to execute
  File "/usr/Python-3.8.2/lib/python3.8/site-packages/MySQLdb/cursors.py", line 206, in execute
    raise ProgrammingError(str(m))
MySQLdb._exceptions.ProgrammingError: not all arguments converted during bytes formatting

重点为两句话

TypeError: not all arguments converted during bytes formatting
MySQLdb._exceptions.ProgrammingError: not all arguments converted during bytes formatting

参数传递的多了的时候,提示没有所有的参数都转换了。与上面的问题相反,这个需要一个参数但是传递了两个

3. datetime 类型不能 json 化

sql = "select `time` from `temp`;"
cur.execute(sql)
data = {"time":[]}
data["time"] += list(cur.fetchall())
data["time"] = [x[0] for x in data["time"]]
print(data)
print(json.dumps(data))
(base) [[email protected] 总结]# python38 1.py
{'time': [datetime.datetime(2020, 6, 17, 0, 23, 39), datetime.datetime(2020, 6, 17, 0, 23, 41), datetime.datetime(2020, 6, 17, 0, 32, 24), datetime.datetime(2020, 6, 17, 0, 33, 16), datetime.datetime(2020, 6, 17, 0, 33, 52), datetime.datetime(2020, 6, 17, 0, 33, 53), datetime.datetime(2020, 6, 17, 0, 35, 6), None]}
Traceback (most recent call last):
  File "1.py", line 20, in <module>
    print(json.dumps(data))
  File "/usr/Python-3.8.2/lib/python3.8/json/__init__.py", line 231, in dumps
    return _default_encoder.encode(obj)
  File "/usr/Python-3.8.2/lib/python3.8/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/Python-3.8.2/lib/python3.8/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "/usr/Python-3.8.2/lib/python3.8/json/encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type datetime is not JSON serializable

datetime 类型,不能被 json 化。这时 data["time"] = [str(x) for x in data["time"]] 处理一下,将其转化成字符串即可

sql = "select `time` from `temp`;"
cur.execute(sql)
data = {"time":[]}
data["time"] += list(cur.fetchall())
data["time"] = [x[0] for x in data["time"]]
data["time"] = [str(x) for x in data["time"]]
print(data)
print(json.dumps(data))

输出如下

{'time': ['2020-06-17 00:23:39', '2020-06-17 00:23:41', '2020-06-17 00:32:24', '2020-06-17 00:33:16', '2020-06-17 00:33:52', '2020-06-17 00:33:53', '2020-06-17 00:35:06', 'None']}
{"time": ["2020-06-17 00:23:39", "2020-06-17 00:23:41", "2020-06-17 00:32:24", "2020-06-17 00:33:16", "2020-06-17 00:33:52", "2020-06-17 00:33:53", "2020-06-17 00:35:06", "None"]}

4. 数据库 commit

sql = "insert into `temp` (`val`, `time`) values (%s, CURRENT_TIMESTAMP());"
cur.execute(sql, (2, ))

但是插入后,数据库仍然没有
最后应该 commit() 一下

conn.commit()

5. 传递元组,一个参数 (x, )

sql = "insert into `temp` (`val`, `time`) values (%s, CURRENT_TIMESTAMP());"
cur.execute(sql, (2))
Traceback (most recent call last):
  File "1.py", line 15, in <module>
    cur.execute(sql, (2))
  File "/usr/Python-3.8.2/lib/python3.8/site-packages/DBUtils/SteadyDB.py", line 605, in tough_method
    result = method(*args, **kwargs)  # try to execute
  File "/usr/Python-3.8.2/lib/python3.8/site-packages/MySQLdb/cursors.py", line 202, in execute
    args = tuple(map(db.literal, args))
TypeError: 'int' object is not iterable

因为 (2) 作为一个元组 2(只有这一个元素) 或者一个算式 (2) == 2,引起歧义。此处python认为是一个算式,结果为原值 2,如果需要声明元组,至少包含两项,即 (2, )

其他坑和经验总结

flask

1. flask 缓存

flask 的缓存,导致图片更新未加载。
解决方案:
1. 修改缓存时间,flask提供了设置属性,参考 Flask 静态文件缓存问题

  1. 加一个 hash(或者其他字符)
@app.route("/getimg", methods=["GET"]) 
    # some code
    # 具体代码不写,功能为 `/getimg?id=xxxx` 的时候,重定向到图片的实际地址。
    return redirect("https://some.api.com/static/images/" + str(id) + ".jpg?timestamp=" + str(time.time()))

如果优化一下,就是不使用当前时间,而是使用文件更新时间。这样也可以发挥缓存的机制。

2. 反代下的IP

由于使用的反向代理(nginx站点 -> 本地某端口),HTTPS 也是 nginx 的配置。因此 flask 接收到的数据,就是处理好了的,来自 127.0.0.1 (可以通过 nginx 配置获取原来 IP,但是不需要)。但是log会有这样的消息

194.61.54.237 - - [15/Jun/2020 23:01:05] "/*àCookie: mstshash=Administr" HTTPStatus.BAD_REQUEST -

(其中 /*àCookie: mstshash=Administr 为紫色)
猜测是通过扫描,按照HTTPS直接访问原来端口所致。

3. flask 的处理速度

目前测试,每秒10+请求,其中一半的是图片几十kb的头像,无压力

1. 统一 API

统一API的形式和接口

2. 注释和文档

形成写注释和文档的习惯

数据库

MySQL 从 CRUD 到 复杂一些的 CRUD

1. join

1. select 的时候,写清楚列

方便修改

微信

  1. 默认头像是获取不到头像路径的
  2. 性别是1男 2女,而后端是1,0

前端

1. cookie

小程序不支持 cookie

解决方案:采用设置全局变量(app.var)或者本地

//app.js
App({
    globalData: {
        cookie: "",
    }
})

在注册成功后,设置本地 globalData 的值。

app.globalData.cookie = data.cookies[0];

同时在需要的时候取出这个值

wx.request({//一个API
    url: 'https://some.api.com/get',
    header: {
        "Cookie": app.globalData.cookie // 传递 cookie
    },
    data: {
        target: uid
    }, success(res) {
        console.log(res)
    }
})

2. wx.request 异步调用

wx.request(/* args_页面信息 */);
wx.request(/* args_评论 */);

两个请求由于是异步操作,所以可能第一个还没有完成就进行了第二个。
也就是可能比如还没有获取到页面信息,就进行了后面获取评论的操作。
简单粗暴的解决方法:第一个的回调函数里面进行第二个代码。

3. POST的 Content-Type

后端直接接收失败,需要制定 content-type

'Content-Type': 'application/x-www-form-urlencoded'

一个POST的例子

wx.request({
    url: 'https://some.api.com/post',
    header: {
        'content-type': "application/x-www-form-urlencoded",
        "Cookie": app.globalData.cookie
    },
    method: "post",
    data: {
        pid: this.data.postId,
    },
    success(res) {
        console.log(res)
    }
})

赞(0)
未经允许不得转载:飞天狒狒 » 微信小程序应用开发赛的总结回顾

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址