首先进行后端开发,根据网上关于docker-easyconnect的使用教程,我首先得买一台Linux服务器,正好之前在哔哩哔哩上有人推荐的阿里云ecs,99元/年,虽然各大公司的云产品的价格相比几年前下降了不少,但我还是咬牙买下了一台 Ubuntu 18.04
1.首先安装docker
curl -fsSL https://test.docker.com -o test-docker.sh
sudo sh test-docker.sh
2.安装docker-easyconnect
sudo yum remove -y docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
sudo yum install -y docker-ce docker-ce-cli containerd.io
sudo systemctl start docker
sudo systemctl enable docker
3.启动docker-easyconnect服务
docker run --device /dev/net/tun --cap-add NET_ADMIN -ti -p 127.0.0.1:1080:1080 -p 127.0.0.1:8888:8888 -e EC_VER=7.6.3 -e CLI_OPTS="-d 教务系统ip -u 学号 -p 校园网密码" hagb/docker-easyconnect:cli
注意,这里的教务系统ip只能是ip格式,可以通过ping 命令来获取ip
现在docker-easyconnect
就算部署成功
我们使用写一个python测试一下是否能正确访问教务系统
import requets
r=requests.post(url=url,data=data,headers=headers,proxies={'http':'127.0.0.1:8888'})
print(r.statuscode)
当statuscode为200时代表部署成功。
下一步是教务系统课表等内容的获取,这个在之前在编写原生Android版好好好课程表时候我已经使用python写好了,由于python也跨平台,我可以使用之前写的脚本。
获取到课程表数据之后我该如何以api的形式返回给客户端呢,我想到了Flask,由于之前部署在网页端的项目几乎都是用Flask搭建的,这个api的搭建对我来说也显得轻车熟路,
下面记录一下踩坑记录以及我是如何解决的
解决:在python文件之前加上下面代码
#!/usr/bin/python
# -*- coding: UTF-8 -*-
解决: 这个问题困扰我半天,我第一反应就是cookie的问题,但是误以为时Flask每次请求后保存的cookie,因为当我直接执行获取课表的py脚本时不会出现这个问题,我网上找了好多资料来清除Flask的cookie,都没有效果,山重水复之际,我将实现转到了py脚本,我尝试了在代码中连续模拟请求两次(不中断程序),结果问题复发了,这说明就是脚本自身问题与Flask无关。
在脚本中,我在结束位置加入以下代码
session.cookies.clear()
清除cookie,最终问题得到解决
当输入表单信息有误时,可能会触发500错误,根据Flask的报错信息,我发现时由于代码中没有做异常处理,于是我对代码进行优化,在可能出现错误的地方进行了判断,极大提高了api的健壮性与容错能力
* Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://127.0.0.1:5000
Press CTRL+C to quit
这些都是由于flask没有运行在稳定的环境
我们可以使用Gunicorn
来帮忙
安装Gunicorn
pip install gunicorn
使用Gunicorn来启动flask服务
gunicorn -b 0.0.0.0:8000 app:app
我们需要安装进程管理软件实现的进程管理,使得在推出服务器之后服务仍然能正常运行,我们这里使用Supervisor
sudo apt-get install supervisor
sudo nano /etc/supervisor/conf.d/gunicorn.conf
[program:gunicorn]
command=/path/to/your/virtualenv/bin/gunicorn -b 0.0.0.0:5000 app:app
directory=/path/to/your/app/directory
user=root
autostart=true
autorestart=true
redirect_stderr=true
stdout_logfile=/var/log/gunicorn.log
确保将上述命令和路径配置为适合您的环境。
保存并关闭文件。
更新 Supervisor 配置并启动进程:
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start gunicorn
这将读取新的配置文件、更新 Supervisor 并启动 gunicorn
进程。
现在,gunicorn
进程将由 Supervisor 管理,并且会在系统启动时自动启动。可以使用 supervisorctl
命令来管理进程,例如停止、重启或查看进程状态:
sudo supervisorctl stop gunicorn
sudo supervisorctl restart gunicorn
sudo supervisorctl status
这里要指定flask服务运行在0.0.0.0
gunicorn -b 0.0.0.0:5000 app:app
并且由于阿里云的安全策略,我们需要在安全组
中开放5000端口
先使用
netstat -tunlp
查看当前运行的服务以及端口
强制关闭
kill -9 pid
这样外网就能访问到啦
基于flutter开发课程表的原因就是因为其跨平台特性,可以运行在web,ios,Windows以及Android端,这样可以极大可能收获用户。
下面记录flutter开发过程中的踩过的坑
这时候只要在终端输入
flutter clean
在调试(debug)模式下不需要网络权限也能获取到课程数据,但是当发布为realease版本后,需要在app manifest 文件中加入网络权限(跟Android原生开发类似)
这样app才能成功访问到网络.
安卓应用发布都需要签名,而我开发的app都使用的我的签名pwxiao.jks,该签名创建后保存在了我的设备上,现在需要使用这个签名对我的flutter app进行签名
这个过程在官网有教程
创建一个名为 [project]/android/key.properties
的文件,它包含了密钥库位置的定义。在替换内容时请去除 < >
括号:
storePassword=
keyPassword=
keyAlias=upload
storeFile=
storeFile
在 Windows 上类似于 C:\\Users\\
。
在以 release 模式下构建你的应用时,修改 [project]/android/app/build.gradle
文件,以通过 gradle 配置你的上传密钥。
android
代码块之前将你 properties 文件的密钥库信息添加进去:content_copy
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android {
...
}
将 key.properties
文件加载到 keystoreProperties
对象中。
buildTypes
代码块: buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now,
// so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}
将其替换为我们的配置内容:
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
现在flutter app 的发布版本就会被自动签名了。
当部署到vercel服务器时,网站会采用https加密,但是获取课表过程中需要向我的服务器请求数据,而我的服务器使用的http协议,没有使用https加密,而有些浏览器(目前已知的有chrome,edge,safari)的安全策略比较严格,会组织这种请求
console输出如下:
main.dart.js:40476 Mixed Content: The page at 'https://app.pwxiao.top/' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://xxxxxxx'. This request has been blocked; the content must be served over HTTPS
目前暂未解决这个问题,网上提到使用nignx反向代理,获取以后会解决
dart语言中
在写一周课表功能的过程中,我发现在web平台能正确加载,而在Android平台则会抛出异常,我通过debug将问题锁定在了下面这一行代码
int VisualstartJie = ((startJie-1)/2) as int;
这段代码一开始我想的是根据课程json中的startJie转换成他在课程表中竖列的坐标,
一开始是这样
int VisualstartJie = ((startJie-1)/2);
但这样可能会有一个问题,当startJie为偶数时,((startJie-1)/2)的值会是浮点数,ide也给出了错误提示,A value of type 'double' can't be assigned to a variable of type 'int'.
于是我通过ide的自动修复在代码后面加上了as int
,这样没有报错,web平台也正常和运行,但是很奇怪这样在Android平台是跑不成的,当我将代码写成
int VisualstartJie = ((startJie-1)/2).toInt();
则能跑通,暂时还不明白两个平台在这方面有什么区别.
颜色应该跟课程名称挂钩,这里使用material.pramary配色,我的方案是取课程名称的hashcode,再对18(也就是配色列表长度)取模,再通过这个值匹配到配色列表中的元素,虽然这样还是可能会出现不同课程配色一样的问题,但是效果上还是符合预期的
Android app不同于网站,不会自动更新,,需要自己编写更新功能,再flutter项目中,会创建有Android项目供自定义安卓端的内容,正好我是从原生安卓转Flutter,并且在之前原生安卓版的好好好课程表项目已经编写了这一功能,故可以直接使用之前的代码。不过还是遇到有一些问题,下面是详细步骤
在之前的更新代码中用到了okhttpy以及json处理等库,在flutter项项目中这些库需要我们自己添加
1.找到moudule为app的build.gradle,添加
dependencies {
implementation 'androidx.annotation:annotation:1.7.1'
...这里添加你需要导入的库
}
点击sync now