关于flask:python-flask初体验

引言以前,学习前端的时候用过nodejs做后端,过后用if...else...写门路判断写的很臃肿。当初想试试其余语言,就选了python试试水。从nodejs到flask相对是个微小的挑战,尤其是对想我这样很久没有看过js的人来说。之前用的nodejs+react,当初有点看不懂了,感叹年老真好。 选型python的支流web框架有django,flask,tornado,twisted。。。年老、轻量、顺口,所以我选用flask。对于什么是web框架能够看下图。wsgi解释一套大家约定的接口标准;wsgi有很多能够抉择的web framework就是各个语言本人规定的一套规范,旨在不便开发人员开发业务相干;http server了解为解决网络协议相干的服务。 看文档的时候,很多web framework也能提供http server。不过,他们也说了,大部分用来debug用,不倡议生产上应用 装置装置flask我应用了centos 8 stream。应用yum命令。 yum install flask装置uWSGI官网:uwsgi官网上述地址是uwsgi对于疾速动手python的文档。装置相干节选如下截图:你很容易看到via pip; pip install uwsgi;。 那么首先,须要取得pip,这意味着咱们须要先装置python(哈哈哈,当然,咱们搞的就是python的web框架) 看一下咱们能装置什么版本 yum list *python* 装置一个能装置的最新的版本 yum install python39 当初,咱们应该能够看到像python3,python3.9,pip等python相干的命令了。 但咱们执行pip install uwsgi的时候会报错。我忘了截图了。不要慌乱,在一堆红字中,他提醒咱们Exception: you need a C compiler to build uWSGI 装置一个c compile yum install gcc但咱们执行pip install uwsgi的时候会报错。我忘了截图了。不要慌乱,在一堆红字中,他提醒咱们fatal error: Python.h: No such file or directory 查看Python development headers yum list *python*devel 找一个和python版本对应的版本,装置Python development headers yum install python39-devel这些都装置实现后,执行pip install uwsgi,应该没有问题了。我装置的时候比拟卡,多执行几次,总能胜利的。其实,uwsgi的文档中写了。再回到这张截图,看下高亮的句子“uWSGI is a (big) C application, so you need a C compiler (like gcc or clang) and the Python development headers.” ...

July 4, 2023 · 1 min · jiezi

关于flask:SpringBoot-如何保证接口安全老鸟们都是这么玩的

为什么要保障接口平安对于互联网来说,只有你零碎的接口裸露在外网,就防止不了接口平安问题。 如果你的接口在外网裸奔,只有让黑客晓得接口的地址和参数就能够调用,那几乎就是劫难。举个例子:你的网站用户注册的时候,须要填写手机号,发送手机验证码,如果这个发送验证码的接口没有通过非凡平安解决,那这个短信接口早就被人盗刷不晓得节约多少钱了。那如何保障接口平安呢?一般来说,裸露在外网的api接口须要做到防篡改和防重放能力称之为平安的接口。防篡改咱们晓得http 是一种无状态的协定,服务端并不知道客户端发送的申请是否非法,也并不知道申请中的参数是否正确。举个例子, 当初有个充值的接口,调用后能够给用户减少对应的余额。http://localhost/api/user/recharge?user_id=1001&amount=10复制代码如果非法用户通过抓包获取到接口参数后,批改user_id 或 amount的值就能够实现给任意账户增加余额的目标。如何解决采纳https协定能够将传输的明文进行加密,然而黑客依然能够截获传输的数据包,进一步伪造申请进行重放攻打。如果黑客应用非凡伎俩让申请方设施应用了伪造的证书进行通信,那么https加密的内容也会被解密。个别的做法有2种: 采纳https形式把接口的数据进行加密传输,即使是被黑客破解,黑客也破费大量的工夫和精力去破解。接口后盾对接口的申请参数进行验证,避免被黑客篡改; 步骤1:客户端应用约定好的秘钥对传输的参数进行加密,失去签名值sign1,并且将签名值也放入申请的参数中,发送申请给服务端步骤2:服务端接管到客户端的申请,而后应用约定好的秘钥对申请的参数再次进行签名,失去签名值sign2。步骤3:服务端比对sign1和sign2的值,如果不统一,就认定为被篡改,非法申请。 防重放防重放也叫防复用。简略来说就是我获取到这个申请的信息之后什么也不改,,间接拿着接口的参数去 反复申请这个充值的接口。此时我的申请是非法的, 因为所有参数都是跟非法申请截然不同的。重放攻打会造成两种结果: 针对插入数据库接口:重放攻打,会呈现大量反复数据,甚至垃圾数据会把数据库撑爆。针对查问的接口:黑客个别是重点攻打慢查问接口,例如一个慢查问接口1s,只有黑客发动重放攻打,就必然造成零碎被拖垮,数据库查问被阻塞死。 对于重放攻打个别有两种做法:基于timestamp的计划每次HTTP申请,都须要加上timestamp参数,而后把timestamp和其余参数一起进行数字签名。因为一次失常的HTTP申请,从收回达到服务器个别都不会超过60s,所以服务器收到HTTP申请之后,首先判断工夫戳参数与以后工夫比拟,是否超过了60s,如果超过了则认为是非法申请。个别状况下,黑客从抓包重放申请耗时远远超过了60s,所以此时申请中的timestamp参数曾经生效了。 如果黑客批改timestamp参数为以后的工夫戳,则sign1参数对应的数字签名就会生效,因为黑客不晓得签名秘钥,没有方法生成新的数字签名。 然而这种形式的破绽也是不言而喻,如果在60s之内进行重放攻打,那就没方法了,所以这种形式不能保障申请仅一次无效。 老鸟们个别会采取上面这种计划,既能够解决接口重放问题,又能够解决一次申请无效的问题。基于nonce + timestamp 的计划nonce的意思是仅一次无效的随机字符串,要求每次申请时该参数要保障不同。理论应用用户信息+工夫戳+随机数等信息做个哈希之后,作为nonce参数。此时服务端的解决流程如下: 去 redis 中查找是否有 key 为 nonce:{nonce} 的 string如果没有,则创立这个 key,把这个 key 生效的工夫和验证 timestamp 生效的工夫统一,比方是 60s。如果有,阐明这个 key 在 60s 内曾经被应用了,那么这个申请就能够判断为重放申请。 这种计划nonce和timestamp参数都作为签名的一部分传到后端,基于timestamp计划能够让黑客只能在60s内进行重放攻打,加上nonce随机数当前能够保障接口只能被调用一次,能够很好的解决重放攻打问题。代码实现接下来以SpringBoot我的项目为例看看如何实现接口的防篡改和防重放性能。1、构建申请头对象@Data@Builderpublic class RequestHeader {   private String sign ;   private Long timestamp ;   private String nonce;}复制代码2、工具类从HttpServletRequest获取申请参数@Slf4j@UtilityClasspublic class HttpDataUtil {    /**     * post申请解决:获取 Body 参数,转换为SortedMap     *     * @param request     */    public  SortedMap<String, String> getBodyParams(final HttpServletRequest request) throws IOException {        byte[] requestBody = StreamUtils.copyToByteArray(request.getInputStream());        String body = new String(requestBody);        return JsonUtil.json2Object(body, SortedMap.class);   }    /**     * get申请解决:将URL申请参数转换成SortedMap     */    public static SortedMap<String, String> getUrlParams(HttpServletRequest request) {        String param = "";        SortedMap<String, String> result = new TreeMap<>();        if (StringUtils.isEmpty(request.getQueryString())) {            return result;       }        try {            param = URLDecoder.decode(request.getQueryString(), "utf-8");       } catch (UnsupportedEncodingException e) {            e.printStackTrace();       }        String[] params = param.split("&");        for (String s : params) {            String[] array=s.split("=");            result.put(array[0], array[1]);       }        return result;   }}复制代码这里的参数放入SortedMap中对其进行字典排序,前端构建签名时同样须要对参数进行字典排序。3、签名验证工具类@Slf4j@UtilityClasspublic class SignUtil {    /**     * 验证签名     * 验证算法:把timestamp + JsonUtil.object2Json(SortedMap)合成字符串,而后MD5     */    @SneakyThrows    public  boolean verifySign(SortedMap<String, String> map, RequestHeader requestHeader) {        String params = requestHeader.getNonce() + requestHeader.getTimestamp() + JsonUtil.object2Json(map);        return verifySign(params, requestHeader);   }    /**     * 验证签名     */    public boolean verifySign(String params, RequestHeader requestHeader) {        log.debug("客户端签名: {}", requestHeader.getSign());        if (StringUtils.isEmpty(params)) {            return false;       }        log.info("客户端上传内容: {}", params);        String paramsSign = DigestUtils.md5DigestAsHex(params.getBytes()).toUpperCase();        log.info("客户端上传内容加密后的签名后果: {}", paramsSign);        return requestHeader.getSign().equals(paramsSign);   }}复制代码4、HttpServletRequest包装类public class SignRequestWrapper extends HttpServletRequestWrapper {    //用于将流保留下来    private byte[] requestBody = null;    public SignRequestWrapper(HttpServletRequest request) throws IOException {        super(request);        requestBody = StreamUtils.copyToByteArray(request.getInputStream());   }    @Override    public ServletInputStream getInputStream() throws IOException {        final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody);        return new ServletInputStream() {            @Override            public boolean isFinished() {                return false;           }            @Override            public boolean isReady() {                return false;           }            @Override            public void setReadListener(ReadListener readListener) {           }            @Override            public int read() throws IOException {                return bais.read();           }       };   }    @Override    public BufferedReader getReader() throws IOException {        return new BufferedReader(new InputStreamReader(getInputStream()));   }}复制代码防篡改和防重放咱们会通过SpringBoot Filter来实现,而编写的filter过滤器须要读取request数据流,然而request数据流只能读取一次,须要本人实现HttpServletRequestWrapper对数据流包装,目标是将request流保留下来。5、创立过滤器实现平安校验@Configurationpublic class SignFilterConfiguration {    @Value("${sign.maxTime}")    private String signMaxTime;    //filter中的初始化参数    private Map<String, String> initParametersMap =  new HashMap<>();    @Bean    public FilterRegistrationBean contextFilterRegistrationBean() {        initParametersMap.put("signMaxTime",signMaxTime);        FilterRegistrationBean registration = new FilterRegistrationBean();        registration.setFilter(signFilter());        registration.setInitParameters(initParametersMap);        registration.addUrlPatterns("/sign/*");        registration.setName("SignFilter");        // 设置过滤器被调用的程序        registration.setOrder(1);        return registration;   }    @Bean    public Filter signFilter() {        return new SignFilter();   }}复制代码@Slf4jpublic class SignFilter implements Filter {    @Resource    private RedisUtil redisUtil;    //从fitler配置中获取sign过期工夫    private Long signMaxTime;    private static final String NONCE_KEY = "x-nonce-";    @Override    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;        HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;        log.info("过滤URL:{}", httpRequest.getRequestURI());        HttpServletRequestWrapper requestWrapper = new SignRequestWrapper(httpRequest);        //构建申请头        RequestHeader requestHeader = RequestHeader.builder()               .nonce(httpRequest.getHeader("x-Nonce"))               .timestamp(Long.parseLong(httpRequest.getHeader("X-Time")))               .sign(httpRequest.getHeader("X-Sign"))               .build();        //验证申请头是否存在        if(StringUtils.isEmpty(requestHeader.getSign()) || ObjectUtils.isEmpty(requestHeader.getTimestamp()) || StringUtils.isEmpty(requestHeader.getNonce())){            responseFail(httpResponse, ReturnCode.ILLEGAL_HEADER);            return;       }        /*         * 1.重放验证         * 判断timestamp工夫戳与以后工夫是否操过60s(过期工夫依据业务状况设置),如果超过了就提醒签名过期。         */        long now = System.currentTimeMillis() / 1000;        if (now - requestHeader.getTimestamp() > signMaxTime) {            responseFail(httpResponse,ReturnCode.REPLAY_ERROR);            return;       }        //2. 判断nonce        boolean nonceExists = redisUtil.hasKey(NONCE_KEY + requestHeader.getNonce());        if(nonceExists){            //申请反复            responseFail(httpResponse,ReturnCode.REPLAY_ERROR);            return;       }else {            redisUtil.set(NONCE_KEY+requestHeader.getNonce(), requestHeader.getNonce(), signMaxTime);       }        boolean accept;        SortedMap<String, String> paramMap;        switch (httpRequest.getMethod()){            case "GET":                paramMap = HttpDataUtil.getUrlParams(requestWrapper);                accept = SignUtil.verifySign(paramMap, requestHeader);                break;            case "POST":                paramMap = HttpDataUtil.getBodyParams(requestWrapper);                accept = SignUtil.verifySign(paramMap, requestHeader);                break;            default:                accept = true;                break;       }        if (accept) {            filterChain.doFilter(requestWrapper, servletResponse);       } else {            responseFail(httpResponse,ReturnCode.ARGUMENT_ERROR);            return;       }   }    private void responseFail(HttpServletResponse httpResponse, ReturnCode returnCode) {        ResultData<Object> resultData = ResultData.fail(returnCode.getCode(), returnCode.getMessage());        WebUtils.writeJson(httpResponse,resultData);   }    @Override    public void init(FilterConfig filterConfig) throws ServletException {        String signTime = filterConfig.getInitParameter("signMaxTime");        signMaxTime = Long.parseLong(signTime);   }}复制代码6、Redis工具类@Componentpublic class RedisUtil {    @Resource    private RedisTemplate<String, Object> redisTemplate;    /**     * 判断key是否存在     * @param key 键     * @return true 存在 false不存在     */    public boolean hasKey(String key) {        try {            return Boolean.TRUE.equals(redisTemplate.hasKey(key));       } catch (Exception e) {            e.printStackTrace();            return false;       }   }    /**     * 一般缓存放入并设置工夫     * @param key   键     * @param value 值     * @param time 工夫(秒) time要大于0 如果time小于等于0 将设置无限期     * @return true胜利 false 失败     */    public boolean set(String key, Object value, long time) {        try {            if (time > 0) {                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);           } else {                set(key, value);           }            return true;       } catch (Exception e) {            e.printStackTrace();            return false;       }   }    /**     * 一般缓存放入     * @param key   键     * @param value 值     * @return true胜利 false失败     */    public boolean set(String key, Object value) {        try {            redisTemplate.opsForValue().set(key, value);            return true;       } catch (Exception e) {            e.printStackTrace();            return false;       }   }} ...

March 13, 2023 · 7 min · jiezi

关于flask:flask-112-移植指南openEuler-2003-LTS-SP1

介绍简要介绍Flask是一个应用 Python 编写的轻量级 Web 利用框架。其 WSGI 工具箱采纳 Werkzeug ,模板引擎则应用 Jinja2 。本案例应用x86_64架构虚拟机,通过评估工具x2openEuler评估flask 1.1.2软件移植到openEuler操作系统的兼容性,并依据评估后果实现软件移植。 开发语言:Python 开源协定:BSD 倡议的版本倡议应用版本为flask 1.1.2。 阐明:本文档实用于flask 1.1.2,其余版本的flask移植步骤也可参考本文档。环境要求操作系统要求操作系统版本openEuler20.03 LTS SP1CentOS7.6装置操作系统如果是全新装置操作系统,装置形式倡议不要应用最小化装置,否则很多软件包须要手动装置,可抉择“Server with GUI”装置形式。装置openEuler操作系统请参考:https://openeuler.org/zh/docs/20.03_LTS_SP1/docs/Installation/installation.html。 兼容性评估获取flask的RPM包wget https://download-ib01.fedoraproject.org/pub/epel/7/x86_64/Packages/p/python36-flask-1.1.2-4.el7.noarch.rpm下载x2openEuler工具下载指引:https://www.openeuler.org/zh/other/migration/部署工具rpm -ivh x2openEuler-2.0.0-1.x86_64.rpm留神:装置rpm时须要应用root用户,且目前须要网络(用于下载安装依赖)留神:依据提醒装置依赖包如bzip2-devel等su x2openEulerx2openEuler redis-db -init顺次录入redis数据库的ip:127.0.0.1端口:6379数据库索引号(0-16):0明码(工具会对明码加密解决):如果redis明码没有设置或者为空时,间接回车即可x2openEuler init source_centos7.6-openEuler20.03-LTS-SP1.tar.gz备注:x2openEuler应用rpm装置实现后会在/opt/x2openEuler目录下带有source_centos7.6-openEuler20.03-LTS-SP1.tar.gz这个默认资源包须要反对centos8.2到openEuler20.03-LTS-SP1的评估,则需获取对应的动态资源包导入,如对应的资源包为source_centos8.2-openEuler20.03-LTS-SP1.tar.gz,导入此包命令:x2openEuler init source_centos8.2-openEuler20.03-LTS-SP1.tar.gz,请示状况抉择对应的资源包扫描软件x2openEuler scan python36-flask-1.1.2-4.el7.noarch.rpm留神要剖析的移植文件须要有可能让x2openEuler用户能够读取的权限扫描实现后会在/opt/x2openEuler/output目录生成html格局的报告查看评估后果软件兼容性评估报告分三块内容展现软件兼容性,别离是依赖包兼容性、C/C++接口兼容性、java接口兼容性,依赖包兼容性反映了软件包装置过程中的间接依赖,非100%表明无奈正确装置;接口兼容性反映的是单个软件运行过程中对其余软件包、动静库或零碎接口的调用变动,非100%表明在某个性能调用时可能会触发异样,未调用到时可能体现失常;局部后果倡议人工复核,最终软件包应用建优先级倡议 openEuler已移植包>openEuler上人工重编译包>centos软件包。 后果:通过报告可知内部接口兼容性100%,依赖包兼容性人工复核后确认缺失,因为该软件包属于python包,倡议应用pip3形式装置依赖及python-flask对应版本。 装置flaskrpm装置因为兼容性报告显示依赖包缺失,尝试间接用下载的rpm包装置做个验证。 [[email protected] test]# yum install -y python36-flask-1.1.2-4.el7.noarch.rpmLast metadata expiration check: 1:39:08 ago on Mon 22 Mar 2021 10:35:29 AM CST.Error: Problem: conflicting requests - nothing provides python36-setuptools needed by python36-flask-1.1.2-4.el7.noarch - nothing provides python(abi) = 3.6 needed by python36-flask-1.1.2-4.el7.noarch - nothing provides python36-click >= 5.1 needed by python36-flask-1.1.2-4.el7.noarch - nothing provides python36-itsdangerous >= 0.24 needed by python36-flask-1.1.2-4.el7.noarch - nothing provides python36-jinja2 >= 2.10.1 needed by python36-flask-1.1.2-4.el7.noarch - nothing provides python36-werkzeug >= 0.15 needed by python36-flask-1.1.2-4.el7.noarch(try to add '--skip-broken' to skip uninstallable packages or '--nobest' to use not only best candidate packages)因为依赖起因未能装置。 ...

November 8, 2022 · 2 min · jiezi

关于flask:Flask-Echarts-制作-仪表盘

下载https://echarts.apache.org/examples/zh/index.html 代码展现html{% extends 'layout.html' %}{% block xx %} <blockquote class="layui-elem-quote"> 看板开发ing <a class="layui-font-blue" href="" target="_blank">other dashboards</a> 的页面,敬请期待。 </blockquote> <fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;"> <legend> Dashboards</legend> </fieldset> <div class="layui-row"> <div class="layui-col-md6"> <div class="grid-demo grid-demo-bg1"> <div id="contest" style="width: 600px;height:400px;"> </div> </div> </div> <div class="layui-col-md6"> <div class="grid-demo"> <div class="layui-bg-gray" style="padding: 30px;"> <div class="layui-row layui-col-space15"> <div class="layui-col-md6"> <div class="layui-card"> <div class="layui-card-header">在线人数 </div> <div class="layui-card-body"> <br> <br> <br> <h1 style="height: 90px;width: 90px;"> {{ login_count_online }}</h1> <br> <br> <br> <br> </div> </div> </div> </div> </div> </div> </div> </div> <div class="layui-row"> <div class="layui-col-xs6"> <div id="main" style="width: 500px;height:400px;" class="grid-demo grid-demo-bg1"></div> </div> <div class="layui-col-xs6"> <div id='tests' style='width:500px;height:400px;' class="grid-demo"></div> </div> </div>{% endblock %}{% block js %} <script type="text/javascript"> // 基于筹备好的dom,初始化echarts实例 var myChart = echarts.init(document.getElementById('contest')); // 指定图表的配置项和数据 var option = { title: { text: 'Resource percentage analysis chart', subtext: 'Resource Data', left: 'center' }, tooltip: { trigger: 'item' }, legend: { orient: 'vertical', left: 'left' }, series: [ { name: 'Access From', type: 'pie', radius: '50%', data: [ {% for data in data_js %} {value:{{ data.value }}, name: '{{data.name}}'}, {% endfor %} ], emphasis: { itemStyle: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0, 0, 0, 0.5)' } } } ] }; myChart.setOption(option); </script> <script type="text/javascript"> // 基于筹备好的dom,初始化echarts实例 var myChart = echarts.init(document.getElementById('main')); // 指定图表的配置项和数据 var option = { title: { text: 'Resource histogram chart' }, tooltip: {}, legend: { data: ['数量'] }, xAxis: { data: {{ data_name|safe }} }, yAxis: {}, series: [{ name: '资产类型', type: 'bar', data: {{ data_value|safe }} }] }; myChart.setOption(option); </script> <script> var myChart = echarts.init(document.getElementById('tests')); var option = { title: {text: '浏览量统计'}, tooltip: {}, legend: {data: ['浏览量']}, xAxis: { data:{{ date|safe }} }, yAxis: {}, series: [{ name: '浏览量', type: 'line', data:{{ value|safe }} }] }; myChart.setOption(option); </script>{% endblock %}flask@dashboard.route('/', methods=['GET'])@login_requireddef index1(): login_count_online = get_keys_pattern_count('login') print('/ wecome! hello', '##login_count_online:', login_count_online, type(login_count_online)) date_list1 = date_list(7) count_login = [] for i in date_list1: login_count = user_login.query.filter(user_login.date_time.like("%%{tdate}%%".format(tdate=i))).count() count_login.append(login_count) resource_dic = db.session.query(func.count(Resources.id), Select.select_name).filter( Resources.parent_id == Select.select_id).group_by(Resources.parent_id).all() # [(2, 'ip'), (5, 'conferenceroomname'), (1, 'server'), (1, 'printer')] data_js = [] data_value = [] data_name = [] for j in resource_dic: l2 = {} l2['value'] = j[0] data_value.append(j[0]) l2["name"] = j[1] data_name.append(j[1]) data_js.append(l2) print("###data_js:", data_js) db.session.close() print("##date_list1:", date_list1, "##count_login:", count_login) print("##data_js", data_js) print("##data_value", data_value) print("##data_name", data_name) print("##login_count_online", login_count_online) return render_template('index.html', date=date_list1, value=count_login, data_js=data_js, data_value=data_value, data_name=data_name, login_count_online=login_count_online)print/ wecome! hello ##login_count_online: 2 <class 'int'>['2022-08-31', '2022-09-01', '2022-09-02', '2022-09-03', '2022-09-04', '2022-09-05', '2022-09-06']###data_js: [{'value': 2, 'name': 'instancehost'}, {'value': 5, 'name': 'conferenceroomname'}, {'value': 1, 'name': 'server'}, {'value': 1, 'name': 'printer'}]##date_list1: ['2022-08-31', '2022-09-01', '2022-09-02', '2022-09-03', '2022-09-04', '2022-09-05', '2022-09-06'] ##count_login: [1, 0, 1, 0, 0, 0, 0]##data_js [{'value': 2, 'name': 'instancehost'}, {'value': 5, 'name': 'conferenceroomname'}, {'value': 1, 'name': 'server'}, {'value': 1, 'name': 'printer'}]##data_value [2, 5, 1, 1]##data_name ['instancehost', 'conferenceroomname', 'server', 'printer']##login_count_online 2 ...

September 6, 2022 · 3 min · jiezi

关于flask:flask-layui-联动选择框-实例

图1图2图3 ormclass Select(db.Model): __tablename__ = 'select_project' # 表名 select_id = db.Column(db.Integer, primary_key=True, autoincrement=True) select_name = db.Column(db.String(200), nullable=False) # 分类名称、不能为空 roles = db.Column(db.Integer, nullable=False) # 级别、不能为空 def single_to_dict(self): return {c.name: getattr(self, c.name) for c in self.__table__.columns} def to_dict(self): model_dict = dict(self.__dict__) del model_dict['_sa_instance_state'] return model_dictclass Resources(db.Model): __tablename__ = 'resources' # 表名 id = db.Column(db.Integer, primary_key=True, autoincrement=True) resources_name = db.Column(db.String(200), nullable=False) # 分类名称、不能为空 parent_id = db.Column(db.Integer, nullable=False) # 父级id、不能为空。###obj转jsondef to_json_all(msg: list): import json data = {} if type(msg) == list: for i in range(len(msg)): temp_dict = {} j = 0 for k, v in msg[i].__dict__.items(): if j > 0: temp_dict[k] = v j += 1 data[i] = temp_dict else: temp_dict = {} j = 0 for k, v in msg.__dict__.items(): if j > 0: temp_dict[k] = v j += 1 data[0] = temp_dict return json.dumps(data, ensure_ascii=False) ...

August 25, 2022 · 2 min · jiezi

关于flask:flask-FlaskAPScheduler-配置计划任务

pip install Flask-APScheduler办法一:__init__.py from flask import Flask# 援用 APSchedulefrom flask_apscheduler import APScheduler# 援用 congfig 配置from config import Config, APSchedulerJobConfig app = Flask(__name__) # 定时工作,导入配置# APSchedulerJobConfig 就是在 config.py文件中的 类 名称。app.config.from_object(APSchedulerJobConfig) # 初始化Flask-APScheduler,定时工作scheduler = APScheduler()scheduler.init_app(app)scheduler.start()config.py#crontabclass APSchedulerJobConfig(object): SCHEDULER_API_ENABLED = True JOBS = [ { 'id': 'No1', # 工作惟一ID 'func': 'app.task_schedule:test_cron', # 执行工作的function名称,app.test 就是 app上面的`test.py` 文件,`shishi` 是办法名称。文件模块和办法之间用冒号":",而不是用英文的"." 'args': '', #如果function须要参数,就在这里增加 'trigger': { 'type': 'cron', # 类型 # 'day_of_week': "0-6", # 可定义具体哪几天要执行 # 'hour': '*', # 小时数 # 'minute': '1', 'second': '17' # "*/3" 示意每3秒执行一次,独自一个"3" 示意每分钟的3秒。当初就是每一分钟的第3秒时循环执行。 } } ]task_schedule.pyimport time, osdef test_cron(): print('Job 17 executed') task_time = time.strftime("%Y-%m-%d %H:%M:%S") ll = 'echo {test1} >> time_test.txt'.format(test1=task_time) os.system(ll) ...

August 23, 2022 · 2 min · jiezi

关于flask:Python-Flask构建微信小程序订餐系统

download:Python Flask构建微信小程序订餐零碎Golang | 模块引入与疾速实现表格的读写业务介绍在很多管理系统下都有不少让后端进行表格进行操作的业务需要,本期就带大家了解一下Golang中如何使用模块引入的,以及讲解怎么疾速的使用excelize库,对表格进行读写创建的。注释配置模块引入环境咱们在期望在vscode终端中也可能使用模块引入,它是 Go 1.11后新版模块治理形式。go env -w GO111MODULE=auto复制代码其 GO111MODULE 可能传送: auto:在其外层且根目录里有 go.mod 文件时,则开启模块反对,否者无模块反对。 on:开启模块反对。 off:无模块反对。 而后,初始化这个我的项目,就会生成一个 go.mod 文件。go mod init excel-demo复制代码 go.mod 是Go 1.11版本引入的官网的包管理工具(之前为 gopath 来治理),它可能理解为前端开发中的 npm 的作用,次要是为理解决没有记录依赖包具体版本查阅艰巨的问题,也极大程度上便利了依赖包的治理。 引入excelize库excelize 是一个用于读写 Microsoft Excel™2007 及更高版本生成的电子表格文档(XLAM / XLSM / XLSX / XLTM / XLTX)的 Go 语言库,而且更新保护频繁且非常好用。引入excelizego get github.com/xuri/excelize/v2复制代码这里因为站点是国外的所以常常会因无法访问而超时。此时,不要慌,咱们换一个国内的代理就好了。go env -w GOPROXY=https://goproxy.cn复制代码创建表格package main import ( "fmt""github.com/xuri/excelize/v2") func createExcel(){ // 创建表格文件f := excelize.NewFile()// 在Sheet1设置A1项的值f.SetCellValue("Sheet1", "A1", "这是Sheet1的A1项")// 创建新的Sheet,命名为Sheet2selectIndex := f.NewSheet("Sheet2")// 在Sheet2设置B2项的值f.SetCellValue("Sheet2", "B2", "这是Sheet2的B2项")// 切换到Sheet2f.SetActiveSheet(selectIndex)// 保存文件if err := f.SaveAs("test.xlsx"); err != nil { fmt.Println(err)}} ...

July 23, 2022 · 2 min · jiezi

关于flask:flask-在后台消费rocketmq

from flask import Flask, requestfrom flask_redis import FlaskRedisimport time, requests, jsonifyfrom rocketmq.client import PushConsumer, ConsumeStatusfrom celery import Celeryimport all_mqfrom concurrent.futures import ThreadPoolExecutor#executor = ThreadPoolExecutor(2)mq = all_mq.RocketMQ()class FlaskApp(Flask): def __init__(self, *args, **kwargs): super(FlaskApp, self).__init__(*args, **kwargs) self._activate_background_job() def _activate_background_job(self): def run_job(): mq.onMessage() t1 = threading.Thread(target=run_job) t1.start()app = FlaskApp(__name__)import json, timefrom rocketmq.client import PushConsumer, dll, ConsumeStatusimport tracebackimport loggingclass RocketMQ(): def __init__(self): logging.basicConfig(level=logging.CRITICAL, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') self.logger = logging.getLogger(__name__) self.consumer = PushConsumer("itxxxconsumer") self.consumer.set_name_server_address("rxx-xxx.com:9876") self.topic_name = "itxx" #缩小日志输入 dll.SetPushConsumerLogLevel("rexxx.com:9876".encode('utf-8'), 1) def callback(self,msg): sdp_status_json = msg.body sdp_status_json1 = sdp_status_json.decode('utf-8') print(sdp_status_json1, msg.id) return ConsumeStatus.CONSUME_SUCCESS def onMessage(self): self.consumer.subscribe(self.topic_name, self.callback) self.consumer.start() while True: time.sleep(2) self.consumer.shutdown() def my_func(test_body): print(test_body) ...

July 11, 2022 · 1 min · jiezi

关于flask:Flask中SQLAlchemy配置SQLite

在泛滥的数据库抉择中,除了mysql频繁被应用外,SQLite也是会被提到的。置信很多人对这种数据库还不是太相熟,所以本篇对配置SQLite的办法做了一个残缺的梳理。大家在装置好SQLAlchemy后,也能够同时实现跟SQLite数据库的连贯操作。上面咱们就具体的配置办法开展详解。 1、应用 pip 装置 Flask-SQLAlchemy: $ pip install flask-sqlalchemy2、接下来,咱们配置一个简略的 SQLite 数据库: $ cat app.py# -*- coding: utf-8 -*- from flask import Flaskfrom flask_sqlalchemy import SQLAlchemy app = Flask(__name__)app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db/users.db'app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = Truedb = SQLAlchemy(app) class User(db.Model): """定义数据模型""" __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(80), unique=True) email = db.Column(db.String(120), unique=True) def __init__(self, username, email): self.username = username self.email = email def __repr__(self): return '<User %r>' % self.username3、这里有几点须要留神: ...

July 11, 2022 · 1 min · jiezi

关于flask:flask中模板引擎怎么用

在咱们对flask的一些引擎应用时,就不得不提到其中的一个默认引擎了。有些初学flask的人对Jinja2还没有应用过,所以不晓得该从何下手。本篇对于这种默认的引擎应用进行了整顿,有对flask模板引擎感兴趣的,能够跟着咱们一起来看看Jinja2的根底操作,具体的内容如下开展。 1、flask默认的模板引擎是Jinja2 目录构造: /application.py/templates /oscuser.html2、实例 application.py#coding=utf-8__author__ = 'duanpeng' import MySQLdbfrom flask import Flask,request,render_template,session, redirect, url_for, escapeapp = Flask(__name__,static_folder='static',static_url_path='/static') #定义首页@app.route('/')def hello_world(): user_agent = request.headers.get('User-Agent') return 'welcom! ,you browser is %s' % user_agent #定义404谬误页面@app.errorhandler(404)def not_found(error): return render_template('error.html'), 404 #定义动静页面@app.route('/user/<username>')def show_user_profile(username): # show the user profile for that user return 'User %s' % username #限度申请形式@app.route('/sayHello',methods=['post'])def sayHello(): return "hello,who are you?"#限度申请只能为get形式@app.route('/touch',methods=['get'])def touch(): return render_template('bank.html') #我的账号页面,与数据库交互,实现动静数据处理@app.route('/myaccount',methods=['get'])def mydata(): try: #加载驱动 连贯数据库 host ->ip port->端口 conn = MySQLdb.connect(host='192.168.1.124',user='root',passwd='abcdef',db='abcdef',port=3306,charset='gb2312') cursor = conn.cursor() cursor.execute("select * from osc_users t where t.login_name = 'rainbow07693'") result = cursor.fetchone() print(result[4]) cursor.close() conn.close() return render_template('oscuser.html',userinfo=result) except MySQLdb.Error,e: print e if __name__ == '__main__':app.run(debug=True)以上就是flask中模板引擎的应用,置信大家曾经对Jinja2的用法有了肯定的意识。平时在课后也能够找无关的材料进行深刻学习。 ...

July 11, 2022 · 1 min · jiezi

关于flask:flask中如何对数据库进行管理

在flask框架里,有许多数据库须要咱们频繁的解决,这样会造成很大的工作工作。咱们能够应用flask-migrate对数据库进行对立的治理,这样就省去了不少人工解决的工夫,上面咱们简略对flask-migrate办法进行理解,而后带来flask中对数据库进行治理的实例代码,具体内容如下。 1、flask-migrate办法 (1)flask-migrate提供了一个能够附加到flask-script的Manager类实例的ManagerCommand类。 (2)应用add_command()增加一个shell命令,并将db、app和user连贯到上下文中。 2、实例 在本文中,咱们应用了flask-script来治理数据库,另外,flask-migrate还反对flask-script的命令行界面,因而能够应用flask-script来对立治理。 #-*- coding:utf-8 -*-#filename: manage.pyfrom flask import Flaskfrom flask_sqlalchemy import SQLAlchemyfrom flask_script import Manager, Shellfrom flask_migrate import Migrate, MigrateCommand app = Flask(__name__)app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///lrh.db' db = SQLAlchemy(app)migrate = Migrate(app, db) manager = Manager(app)manager.add_command('db', MigrateCommand) class User(db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(128)) def make_shell_context(): return dict(app=app, db=db, User=User) manager.add_command("shell", Shell(make_context=make_shell_context)) if __name__ == '__main__':manager.run()以上就是flask中对数据库进行治理的办法,能够发现通过整顿的数据库,在应用上更为方面,大家学会后也快点对数据库进行治理吧。

July 11, 2022 · 1 min · jiezi

关于flask:flask中Login的使用

Flask-Login,简略的来说,就是一个用户登录页面的设置,能够说通过这种办法,咱们能够对沉闷用户和不沉闷用户授予不同的权限。同时在会话的平安上有所保障。上面咱们就Login的一些应用益处进行介绍,而后带来具体的Login应用实例供大家学习,一起来看看具体的内容吧。 1、Login的益处 会话中积攒的沉闷用户能够轻松登录。 能够限度未登录的用户拜访页面。 解决记住我的性能。 爱护对话cookie不被小偷偷走。 轻松集成到Flask-Principal或其余许可扩大。 2、应用实例 将须要提供一个user_loader 回调。这个回调用于通过在会话中存储的ID来加载用户对象,它应该应用用户的 unicode ID ,并返回绝对应的用户对象。例如: @login_manager.user_loaderdef load_user(userid):return User.get(userid)它应该返回 None ( 不要抛出一个异样) 如果ID有效. (在这种状况下,ID应该手动的进行删除而后解决为持续运行。) 一旦用户认证通过,你能够通过函数 login_user 进行登入,例如: @app.route("/login", methods=["GET", "POST"])def login():form = LoginForm()if form.validate_on_submit():# login and validate the user...login_user(user)flash("Logged in successfully.")return redirect(request.args.get("next") or url_for("index"))return render_template("login.html", form=form)它是如此简略。 你能够通过 current_user 代理获取用户,这个代理在整个模板中都是无效的: {% if current_user.is_authenticated() %} Hi {{ current_user.name }}!{% endif %}页面如果须要用户登录才能够拜访能够应用 login_required 装璜器: @app.route("/settings")@login_requireddef settings():pass当用户须要登出时: @app.route("/logout")@login_requireddef logout():logout_user()return redirect(somewhere)它们行将登出,会话中的cookie将被全副革除。 以上就是flask中Login的应用,如果大家没有据说的Login,无妨先就它进行一些根底的理解,而后再来领会它的用途。

July 11, 2022 · 1 min · jiezi

关于flask:Flask中login如何定制登陆过程

一般来说,用户对于本人可能设置的页面,还是充斥极大的趣味。就拿Flask中login的登录过程来说,是能够依据本人的需要,做一些应用上的调整的。鉴于很多人会对定制的登录过程感兴趣,这里为大家进行了具体的流程梳理,想要同样实现这种个性化的定制,一起往下看看办法吧。 默认状况下,当用户登录到须要login_required身份验证的页面,但此时用户没有登录时,Flask-Login将闪动一条音讯,并将它们导航到登录视图(如果未设置登录视图,它将报告401谬误) 1、登录视图的名称能够应用登录管理器来设置,例如: login_manager.login_view = "users.login"2、默认的闪现音讯时请登陆后再查看该页面。 如果定制该信息,请应用, LoginManager.login_message: login_manager.login_message = u"Bonvolu ensaluti por uzi tio paĝo."3、定制信息的目录,请应用LoginManager.login_message_category : login_manager.login_message_category = "info"视图中有1个next选项指向您想查看的页面,当登入后,它会间接跳转到您要查看的页面。 4、如果您想进一步定制该流程,请应用函数 LoginManager.unauthorized_handler: @login_manager.unauthorized_handlerdef unauthorized():# do stuffreturn a_response以上就是Flask中login定制登陆过程的办法,基本上跟着流程走不会有太大的问题,看完后也赶快入手来试一试吧。

July 11, 2022 · 1 min · jiezi

关于flask:Flask中Jinja2是什么

在Flask框架里,有一种模板大家看起来十分眼生,那就是Jinja2。如果在django有接触过模板,那么对这Jinja2模板的上手就十分轻松了,在应用方面的学习也能够多多少少有所继承。上面咱们就Flask中Jinja2先进行介绍的阐明,理解其一些的有些后,正式进行应用的实例。 1、阐明 Jinja2是Flask作者开发的模板零碎。它最后是一个模拟django模板的模板引擎,为Flask提供模板反对。它因其灵活性、速度和安全性而失去广泛应用。 2、长处 绝对于Template,jinja2更加灵便,它提供了控制结构,表达式和继承等。 绝对于Mako,jinja2仅有控制结构,不容许在模板中编写太多的业务逻辑。 绝对于Django模板,jinja2性能更好。 Jinja2模板的可读性很棒。 3、实例 test.py # 1.导入依赖包from flask import Flask, render_template # 2.实例化app app = Flask(__name__) # 3.映射,默认状况下flask从templates文件夹中寻找模板文件(index.html) @app.route('/') def index(): return render_template('index.html') @app.route('/user/<param>') def user(name): return render_template('index.html', param=param)以上就是Flask中Jinja2的无关介绍,如果在之前没有接触过模板,能够先就相干的知识点进行了解,学会后运行代码局部就能够领会Jinja2的应用。

July 11, 2022 · 1 min · jiezi

关于flask:Flask-Web-极简教程四-Flask-WTF-Froms

一、表单表单在页面中次要负责数据采集,一个表单有三个根本组成部分: 表单标签:这外面蕴含了解决表单数据所用CGI程序的URL以及数据提交到服务器的办法。 表单域:蕴含了文本框明码框、暗藏域多行文本框、复选框单选框下拉抉择框和文件上传框等。表单按钮:包含提交按钮、复位按钮和个别按钮;用于将数据传送到服务器上的CGI脚本或者勾销输出,还能够用表单按钮来管制其余定义了解决脚本的解决工作 常见的表单有注册表单、登录表单、搜寻表单等视图函数中获取表单数据的形式有两种: GET申请提交的表单:request.args.get('name', None)POST申请提交的表单:request.from.get('age', None) 二、WTF表单WTF 表单是一个第三方的库,能够通过Python代码生成表单,而Flask-WTF则是Flask集成了WTF表单性能的实现。 Flask-WTF能够实现这些性能, 集成 wtforms。带有 csrf 令牌的平安表单。全局的 csrf 爱护。反对验证码(Recaptcha)。与 Flask-Uploads 一起反对文件上传。国际化集成。 更多信息能够查看 Flask-WTF 官网。Flask-WTF须要通过装置才能够应用。pip3 install Flask-WTF 在Pycharm中创立新的Flask我的项目flask-wtf,要应用Flask-WTF须要在app.py中创立Flask对象之后增加如下配置, 配置WTF的CSRF,Value能够是任意的字符串app.config['WTF_CSRF_SECRET_KEY'] = 'abc21231fafae2' 第一个表单模型在我的项目目录下新建一个form.py文件,专门用来编写表单模型,以登录表单为例,新增一个LoginForm对象,并减少相应的属性from flask_wtf import FlaskFormfrom wtforms import StringField, PasswordField, SubmitField class LoginForm(FlaskForm): username = StringField(label='用户名')password = PasswordField(label='明码')submit = SubmitField(label='提交')表单字段的罕用外围属性如下 属性名属性作用labelform表单中的label标签,如输入框前的文字描述default表单中输入框的默认值validators表单验证规定widget定制界面的显示方式description帮忙文字在app.py中减少视图函数from flask import Flask, render_templatefrom form import LoginForm @app.route('/form')def form(): login_form = LoginForm()# 返回login_form表单模型,在form.html中进行渲染return render_template('form.html', login_form=login_form)在templates减少form.html<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"/><title>Form</title></head><body><h3>登录</h3><form action=""> {# 渲染LoginForm表单模型中username字段的label属性#}{{ login_form.username.label }}:{{ login_form.username }} <br>{{ login_form.password.label }}:{{ login_form.password }} <br>{{ login_form.submit }}</form></body></html> ...

July 1, 2022 · 1 min · jiezi

关于flask:flask-配置ldap模块来校验AD用户登陆

参考flask_simpleldap模块的文档: https://github.com/alexferl/f... 从下面github下载代码,放到我的项目中 此处正文能够查看其他人的用户名明码 “”“谨慎不要外传”“”from flask import Flask, gfrom flask_simpleldap import LDAPapp = Flask(__name__)app.config["LDAP_HOST"] = "10.x1.1xx.11" # defaults to localhostapp.config["LDAP_BASE_DN"] = "OU=xxhu-sh,DC=xiaxxxhu,DC=sh"app.config["LDAP_USERNAME"] = "CN=ixxp,OU=Sxxxount,DC=xxxxxu,DC=sh"app.config["LDAP_PASSWORD"] = "uxxxP"ldap = LDAP(app)@app.route("/")@ldap.basic_auth_requireddef index(): return "Welcome, {0}!".format(g.ldap_username)if __name__ == "__main__": app.run(host="0.0.0.0", port=9000)

April 14, 2022 · 1 min · jiezi

关于flask:如何在Flask中集成Dash应用

背景Plotly Dash 是一个Python web利用框架,它能帮忙咱们疾速建设难看的,响应式的,可交互的,数据可视化页面。惋惜的是,一个只能展现数据的利用并不总是非常有用。如果咱们须要一个残缺的web利用,那就不得不想方法利用它的后端 Flask. 问题只管Dash借了Flask的壳,但这个Flask运行在sandbox里,而且和一般的Flask相比也少了很多性能。比方以下的性能要不没有要不须要降级到Dash enterprise版本。 数据库集成认证多页面、多路由反对自定义格调等等设计为了克服以上的所有问题,与其利用Dash自带的Flask,咱们齐全能够创立一个根底的Flask利用,而后将咱们的Dash利用置于其上。 准则灵便 -- 可能用Dash和Flask创立任意类型的利用。全功能 -- Dash和Flask都必须是全功能的,不能有性能上的限度。可定制 -- 可能自定义利用的款式。简洁 -- 可能简略快捷的创立一个Dash利用。解决方案总的来说,咱们能够有两种形式实现目标。 __子利用__: 创立一个根底的Flask利用,用这个Flask作为parent server初始化Dash利用,将Dash利用用自定义路由注册为子利用。__iframe__: 创立一个根底的Flask利用,将Dash利用放在一个iframe中,再用Flask去加载这些iframe.哪个更好和将Dash利用放在iframe中相比,只管这种形式看起来最简略,然而因为iframe齐全隔离的个性,反而会引入其余问题: __难于定制__: iframe不能通过css/js扭转iframe内的利用。__不统一__: iframe因为和main frame有着不同的路由零碎,点击一个iframe外部的链接并不会触发main frame的跳转。__无奈扩大__: iframe计划不反对多页面的Dash利用。基于以上理由,咱们认为应用子利用是一个更灵便且更普适的计划。 代码构造根底Flask的代码构造如下: ├── app│ ├── dash_apps -- 所有的Dash利用都在这个目录│ │ ├── custom_dash_app.py│ │ ├── experiment_detail_dash_app.py│ │ ├── experiment_list_dash_app.py│ │ └── __init__.py│ ├── __init__.py│ ├── static│ │ └── styles.css -- Custom CSS styles│ ├── templates│ │ ├── dash_layout.html -- Dash利用的layout│ │ ├── header.html -- Header│ │ ├── index.html -- 主页面│ │ └── layout.html -- 主页面的layout│ └── views.py -- Flask路由和主页面导航菜单定义├── config.py├── poetry.lock├── poetry.toml├── pyproject.toml├── README.md├── scripts│ ├── fix.sh│ ├── run.sh│ └── setup.sh├── setup.cfg└── wsgi.py残缺demo实现请参考github。 ...

March 11, 2022 · 2 min · jiezi

关于flask:无脑吹FastAPI性能碾压Flask关于网上不合适的性能对比以及让我糊涂的自测结果

不止一次的听过,有个FastAPI框架,性能碾压Flask,直追Golang,不过始终没有测试过,明天闲着没事测试一下看看后果。不晓得是哪里出了问题,后果大跌眼镜。 测试之前为了偷懒,天然想先从网上找找前人的测试代码以作为参照。百度前几名对于FastAPI和Flask性能测试又带了代码的有上面几个: FastAPI、Flask、Golang性能测试Flask、Django、Tornado、FastAPI 之 Python Web 并发测试flask,tornado,fastapi 压测比拟(web框架)有点纳闷简略看了一下,没明确,为什么都用了unicorn启动FastAPI,却只用Flask自带的启动形式,为什么不必其余WSGI服务器? 我感觉这样应该是有问题的,且不说原本二者都不是同一档次的框架(FastAPI是基于Starlette的,这才是应该和Flask比照的框架),就算比照,也应该用差不多的启动形式吧? unicorn是个第三方ASGI服务器,Flask应该用一个第三方WSGI服务器来启动才失常吧?感觉用它自带的WSGI服务器比可能不太偏心。 我原本想用gunicorn来启动Flask进行比照的,后果发现不兼容Windows,所以换了个waitress,差不多的WSGI框架。 开始测试网上都是用AB测试的,我电脑没装Apache,就用了另一个测试工具siege。测试形式为不限连接数,测试10秒,命令如下: ./siege.exe -b -t10s http://127.0.0.1:5000/测试代码和之前搜到的一样,用二者官网的例子,输入HelloWorld,略作批改,把启动代码写进文件内,就不必应用命令行启动了。 Flask from flask import Flaskfrom waitress import serveapp = Flask(__name__)@app.route('/')def index(): return {'message': 'hello world'}if __name__ == '__main__': app.run(host='0.0.0.0') # serve(app, host='0.0.0.0', port=5000)FastAPI from fastapi import FastAPIimport uvicornapp = FastAPI()@app.get("/")async def read_root(): return {"Hello": "World"}if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=5000)测试后果鉴于网上的文章在那摆着,所以我也测试了一下应用Flask自带启动形式的后果。 除此之外,还测试了FastAPI应用异步的后果(就加了个async,理论应该什么没用的,文档中明确说了,只有函数外部应用了异步函数且须要同步返回时,也就是须要在外部用await时,才须要定义async)。 后果如下: flask Transactions: 4579 hitsAvailability: 100.00 %Elapsed time: 9.15 secsData transferred: 0.11 MBResponse time: 0.03 secsTransaction rate: 500.66 trans/secThroughput: 0.01 MB/secConcurrency: 14.93Successful transactions: 4579Failed transactions: 0Longest transaction: 0.10Shortest transaction: 0.02flask + waitress ...

December 5, 2021 · 2 min · jiezi

关于flask:如何编写一个-Python-Web-应用-一Flask

对于 Flask 最外围的有三点: Application Context: 将整个利用连成一体.View Function & CLI Command: 利用暴漏给外界的操作接口Blueprints (蓝图): 实现模块化开发当然还有其余细节,但有了这三点,就能够编写一个残缺的 Web 援用了 Application Context参考: Flask 2.0.x 我更习惯应用 工厂模式 创立 Context: 在 __init__.py 中写 create_app(): from flask_sqlalchemy import SQLAlchemydb = SQLAlchemy()def create_app(test_config=None): # create and configure the app app = Flask(__name__, instance_relative_config=True) configure(app, test_config) db.init_app(app) from faq.blueprints import review app.register_blueprint(review.bp) return app当在命令行输出命令 flask run 时, flask 将主动寻找 create_app 函数来执行, 以创立 Application Context. PS: flask run 便是一个默认的 CLI Command ...

August 19, 2021 · 2 min · jiezi

关于flask:Flask快速入门后台写接口API

Flask是一个应用Python编写的轻量级Web利用框架。 其WSGI工具箱采纳Werkzeug,模板引擎则应用Jinja2。Flask应用BSD受权。Flask也被称为“microframework”,因为它应用简略的外围,用extension减少其余性能。首先介绍Flask装置:进入创立的虚拟环境,在虚拟环境中应用pip install xxx 进行flask装置。应用flask进行输入hello world!输入后果中127.0.0.1代表本地,本人电脑中运行。5000代表端口号,点击链接输入hello world!。批改路由:绑定路由为/index!凋谢其余主机对其进行拜访,增加host=“0.0.0.0” 绑定路由,<>中内容默认格局为字符串类型,可输出英文、中文、数字等,但输入类型也为字符串类型,设置变量为username,应用%s占位输入hey flask。 批改定义变量类型为int(还可批改为float、path、uuid等类型)。批改为int类型后可进行变量的运算。Flask重定向,应用redirect()函数能够重定向,拜访对应路由即可进入想转入的网站,如下图拜访路由:/易华录开发者社区即转入开发者社区官网。 装置Postman,Postman 是一种罕用的接口测试工具,能够发送简直所有类型的HTTP申请。下图为其主页面。这里能够抉择申请类型,如下图展现其中局部:四种根本申请:1、GET申请会向数据库发索取数据的申请,从而来获取信息,该申请就像数据库的select操作一样,只是用来查问一下数据,不会批改、减少数据,不会影响资源的内容,即该申请不会产生副作用。无论进行多少次操作,后果都是一样的。查看:GET /url/xxx 2、与GET不同的是,PUT申请是向服务器端发送数据的,从而扭转信息,该申请就像数据库的update操作一样,用来批改数据的内容,然而不会减少数据的品种等,也就是说无论进行多少次PUT操作,其后果并没有不同。更新:PUT /url/xxx 3、POST申请同PUT申请相似,都是向服务器端发送数据的,然而该申请会扭转数据的品种等资源,就像数据库的insert操作一样,会创立新的内容。简直目前所有的提交操作都是用POST申请的。创立:POST /url 4、DELETE申请顾名思义,就是用来删除某一个资源的,该申请就像数据库的delete操作。删除:DELETE /url/xxx应用GET申请,输出想要拜访的路由地址,send进行拜访,例如咱们拜访易华录开发者社区官网:POST申请: 输入后果:若想返回后果为json格局,咱们要导入jsonify可实现返回格局为json,如下图:当输入报错时,咱们能够将报错起因进行输入,如下图将age参数删除,咱们可失去“短少参数”的反馈。当咱们将age类型写为str类型,无奈进行运算,咱们将失去“出错”反馈。session模仿简略登录、退出登录、查看登陆状态。登录:首先导入session包,设置session密钥在此设置username和password固定值,当输出username和password值均正确时,反馈登陆胜利。当账号或明码谬误时,反馈“账号或明码谬误”。查看登录状态: 退出登录:当咱们登录实现后,查看登陆状态,反馈失去username。当咱们退出登陆后,再查看一遍登陆状态。 到此,咱们就简略的模仿了账户的登录、查看登录状!

August 18, 2021 · 1 min · jiezi

关于flask:flask关于跨域的问题

拜访后端域名提醒:The 'Access-Control-Allow-Origin' header contains multiple values 'http://localhost:8080, *', but only one is allowed. response header能够看到Access-Control-Allow-Origin有俩个,这是因为web框架中也设置了跨域返回导致的,把flask_cors插件去掉就是了

July 20, 2021 · 1 min · jiezi

关于flask:FlaskLimiter详细使用说明

本文首发于:行者AI速率限度通常作为服务的进攻措施予以施行。服务须要爱护本身免得适度应用(无论是无意还是无心),从而放弃服务可用性。在Flask我的项目开发过程中,遇到了须要对接口进行限度的需要,又不想去造轮子,这时候就须要用到Flask-Limiter这个三方库。本文将对Flask-Limiter的应用进行具体阐明。 1. 装置装置依赖环境。 pip install Flask==1.1.1 Flask-Limiter==1.42. 疾速开始有两种形式示意速率限度: "100 per day"、"20 per hour"、"5 per minute"、"1 per second""100/day"、"20/hour"、"5/minute"、"1/second"速率限度能够设置全局配置,针对所有接口进行限度;也能够通过装璜器进行部分限度;对于不想限度的接口,能够通过装璜器@limiter.exempt进行解除限制。示例代码如下所示: app = Flask(__name__)# 该配置为全局配置、实用于所有接口limiter = Limiter(app, key_func=get_remote_address, default_limits=["100 per day", "10/hour"])# @limiter.limit: 将笼罩全局limiter配置@app.route("/slow")@limiter.limit("1 per day")def slow(): return ":("# override_defaults: 示意该limiter是否笼罩全局limiter限度,默认为True@app.route("/medium")@limiter.limit("1/second", override_defaults=False)def medium(): return ":|"# 残缺继承全局limiter配置@app.route("/fast")def fast(): return ":)"# @limiter.exempt: 被装璜的视图不受全局速率限度@app.route("/ping")@limiter.exemptdef ping(): return "PONG"3. 装璜器依据集体爱好和应用场景,有以下几种形式:繁多润饰:限度字符串能够是单个限度,也能够是定界符分隔的字符串。 @app.route("....")@limiter.limit("100/day;10/hour;1/minute")def my_route() ...多个装璜器:限度字符串能够是单个限度,也能够是定界符分隔的字符串,也能够是两者的组合。 @app.route("....")@limiter.limit("100/day")@limiter.limit("10/hour")@limiter.limit("1/minute")def my_route(): ...自定义性能:默认状况下,依据Limiter实例初始化时所应用的要害性能来利用速率限度。开发者能够实现本人的性能。 def my_key_func(): ...@app.route("...")@limiter.limit("100/day", my_key_func)def my_route(): ...动静加载限度的字符串:在某些状况下,须要从代码内部的源(数据库,近程api等)中检索速率限度。这能够通过向装璜器提供可调用对象来实现。 留神:所装璜的路由上每个申请都会调用提供的可调用对象,对于低廉的检索,请思考缓存响应。 def rate_limit_from_config(): return current_app.config.get("CUSTOM_LIMIT", "10/s")@app.route("...")@limiter.limit(rate_limit_from_config)def my_route(): ...4. 限度域指依据什么进行限度,对应的参数为key_func,flask_limiter.util提供了两种形式: ...

June 15, 2021 · 1 min · jiezi

关于flask:flask-web-实现-harbor-早期版本的镜像-tag-批量-可视化-删除

性能展现 代码展现app.py#! /usr/bin/env python3# -*- coding:utf-8 -*-from flask import Flask, request, render_template, redirect, url_for, make_response ,escape, session, flash, g, current_app, abort, jsonify, send_fileimport requests#from werkzeug.utils import secure_filenameimport os,time, platformfrom flask_wtf import Form#from wtforms import TextField#from shell import os_scrpict, harbor#import sqlite3#from pathlib import Pathfrom flask_sqlalchemy import SQLAlchemyapp = Flask(__name__)# 本脚本只是harbor页面tags清理# cd /usr/local/src/harbor && docker-compose stop #敞开harbor# 物理清理:docker run -it --name gc --rm --volumes-from registry goharbor/registry-photon:v2.6.2-v1.6.3 garbage-collect /etc/registry/config.yml#docker-compose up -d #启动class RequestClient(object): def __init__(self, login_url, username, password): self.username = username self.password = password self.login_url = login_url self.session = requests.Session() self.login() def login(self): requests.packages.urllib3.disable_warnings() self.session.post(self.login_url, params={"principal": self.username, "password": self.password}, verify=False)class ClearHarbor(object): def __init__(self, harbor_domain, username, password, num, schema="http", ): self.num = num self.schema = schema self.harbor_domain = harbor_domain self.harbor_url = self.schema + "://" + self.harbor_domain self.login_url = self.harbor_url + "/login" self.api_url = self.harbor_url + "/api" self.pro_url = self.api_url + "/projects" self.repos_url = self.api_url + "/repositories" self.username = username self.password = password self.client = RequestClient(self.login_url, self.username, self.password) def __fetch_pros_obj(self): # 获取所有项目名称 self.pros_obj = self.client.session.get(self.pro_url).json() # for n in self.pros_obj: # print("分组:",n.get("name")) print(self.pros_obj) return self.pros_obj def get_pros_id(self): # 获取所有我的项目ID self.pros_id = [] pro_res = self.__fetch_pros_obj() for i in pro_res: self.pros_id.append(i['project_id']) # print("所有我的项目ID:",self.pros_id) return self.pros_id def get_del_repos_name(self, pro_id): # 镜像tag数量大于self.num的镜像仓库名称 self.del_repos_name = [] repos_res = self.client.session.get(self.repos_url, params={"project_id": pro_id}) # print("我的项目信息:",repos_res.json()) for repo in repos_res.json(): if repo["tags_count"] > self.num: # print("镜像仓库名称:",repo['name']) self.del_repos_name.append(repo['name']) return self.del_repos_name def fetch_del_repos(self, repo_name): # 删除镜像仓库tag self.del_res = [] tag_url = self.repos_url + "/" + repo_name + "/tags" # 我的项目镜像仓库的所有tags,按创立工夫排序 tags = self.client.session.get(tag_url).json() tags_sort = sorted(tags, key=lambda a: a["created"]) # print(len(tags_sort),tags_sort) # 除了最新的self.num个,其余的tag都增加到待删除列表del_tags del_tags = tags_sort[0:len(tags_sort) - self.num] # print(del_tags) for tag in del_tags: del_repo_tag_url = tag_url + "/" + tag['name'] # print(del_repo_tag_url) del_res = self.client.session.delete(del_repo_tag_url) self.del_res.append("镜像: %s 删除状态: %s" % (del_repo_tag_url,del_res)) return self.del_res def work(self): # 遍历project id for i in self.get_pros_id(): # 获取所有tag超过self.num的repos repos = self.get_del_repos_name(i) if repos: for repo in repos: del_repos = self.fetch_del_repos(repo) print(del_repos) print(repo) def list_repositories(self, pro_id): # 镜像tag数量大于self.num的镜像仓库名称 self.del_repos_name1 = [] repos_res = self.client.session.get(self.repos_url, params={"project_id": pro_id}) # print("我的项目信息:",repos_res.json()) for repo in repos_res.json(): #if repo["tags_count"] > self.num: #print(repo,"镜像仓库名称:",repo['name']) #self.del_repos_name1.append({"name": repo["name"], "tags_count": repo["tags_count"]}) self.del_repos_name1.append({"name": repo["name"], "tags_count": repo["tags_count"],"project_id": repo["project_id"]}) #print(self.del_repos_name1) return self.del_repos_name1 def list_pros(self): # 获取所有我的项目ID self.pros_idname = [] pro_res = self.__fetch_pros_obj() for i in pro_res: self.pros_idname.append({"project_id": i["project_id"], "name": i["name"], "repo_count": i["repo_count"] }) #print(self.pros_idname) #print(self.pros_idname[0]['name']) return self.pros_idname def work_list(self, pros_id_list): # 遍历project id for i in pros_id_list: # 获取所有tag超过self.num的repos repos = self.get_del_repos_name(i) if repos: for repo in repos: # del_repos = self.fetch_del_repos(repo) # print(del_repos) print(repo)@app.route('/harbor/', methods = ['GET', 'POST'])def harbor_list(): del_images_tag = ClearHarbor(harbor_domain="172.16.167.11", username="admin", password="Harbor12345", num=10) harbor_project = del_images_tag.list_pros() print("###########",harbor_project) return render_template('harbor.html', harbor_project1 = harbor_project)@app.route('/del_harbor_project_all/')def del_harbor_project_all1(): del_images_tag = ClearHarbor(harbor_domain="172.16.167.11", username="admin", password="Harbor12345", num=10) del_images_tag.work() return redirect('/harbor/')@app.route('/del_harbor_project/<int:project_id>')def del_harbor_project(project_id): del_images_tag = ClearHarbor(harbor_domain="172.16.167.11", username="admin", password="Harbor12345", num=10) del_reposname = del_images_tag.get_del_repos_name(project_id) print(del_reposname,"#####################",project_id) del_reposname_status = del_images_tag.fetch_del_repos(del_reposname) print(del_reposname_status) return redirect('/harbor/')@app.route('/del_harbor_project_list/', methods = ['GET', 'POST'])def del_harbor_project_list(): if request.method == 'POST': project_id_list = request.form.getlist('vals') #print(project_id_list) vals_list2 = [] for i in project_id_list: if i == '': print("i is none") else: vals_list2.append(i) del_images_tag = ClearHarbor(harbor_domain="172.16.167.11", username="admin", password="Harbor12345", num=10) del_images_tag.work_list(vals_list2) return redirect('/harbor/')@app.route('/harbor_repositories/<int:project_id>')def harbor_repositoriest(project_id): del_images_tag = ClearHarbor(harbor_domain="192.168.1.17", username="admin", password="xxxxxx", num=10) harbor_project = del_images_tag.list_repositories(project_id) print("###########",harbor_project) return render_template('harbor_repositories.html', harbor_project1 = harbor_project)@app.route('/del_repositories_url/<int:project_id>/<path:project_name>')def del_repositories_url(project_id,project_name): del_images_tag = ClearHarbor(harbor_domain="192.168.1.17", username="admin", password="xxxxxx", num=10) del_reposname_status = del_images_tag.fetch_del_repos(project_name) print(del_reposname_status) return redirect('/harbor_repositories/{tproject_id}'.format(tproject_id=project_id))if __name__ == '__main__': app.run() #app.run(host="172.16.117.33",port=5888)harbor.html<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title></head><body> <script src="/static/jquery-1.9.1.min.js"></script> <script> $('#out').click(function () { $.ajax({ url: '/dns_list/', type: 'GET', data: {}, success: function (data) { //期待解决完结主动调用,data-返回值 console.log(data); window.location.href = "url" } }) }); $('#back').click(function () { $.ajax({ url: '/dns_list/', type: 'GET', data: {}, success: function (data) { window.location.href = "/" } }) });function getValues_del_project() { var valArr=[]; var ones=document.getElementsByName('item'); for (var i=0;i<ones.length;i++){ if (ones[i].checked==true){ valArr[i]=ones[i].value } } if (valArr.length!=0){ // var vals = valArr.join(','); // alert(valArr); // var url2 = '/app_intstall/' $.ajax({ url:"/del_harbor_project_list/", type:'POST', contenType:'application/json',// #不加这个,ajax会将后果后边加个[],例如{'vals[]':[4,6,8]} traditional:true,// #不加这个,会报服务器终止了一个在运行的程序 async: false, data:{ 'vals':valArr }, success:function(){ alert("批量革除project 超过10个 tag 胜利"); // window.location.href =url2 }, error:function(){ alert("批量革除project 超过10个 tag 失败"); } }) } else { var error_m="请抉择数据"; alert(error_m); }} </script> <div class="container" style="position: absolute;left: -2%;width: 1590px;height: 850px;margin-left: 95px;"> <h2>harbor</h2> <div style="float: left; width:190px;height:70px"> <ul class='myul'> <li><a class="btn btn-success input-sm" href="/harbor/" onclick="getValues_del_project()"> 批量革除选中我的项目images </a> </li> </ul> </div> <div style="float: left; width:290px;height:40px;display:block;overflow-y:auto;"> <ul class='myul'> <li> <a class="btn btn-primary input-sm" href="/del_harbor_project_all/"> 革除all project >10 tag images </a> </li> </ul> </div> {# <div style="position: absolute;top: 12%;left: 65%;width: 590px;height: 650px;">#} {# <p>text: <textarea rows="41" cols="80" name="conftext"> {{ conflook.conflook }} </textarea></p>#} {# </div>#} <table class="table table-condensed" id="table1"> <thead> <tr> <th width="25"><input id="checkAll" onclick="checkAll()" type="checkbox"></th> <th>ID</th> <th>我的项目</th> <th>镜像仓库数</th> <th>操作</th> </tr> </thead> <tbody> {% for ele in harbor_project1 %} <tr> <td><input name="item" onclick="checkOne()" type="checkbox" value="{{ele.project_id}}"></td> <td>{{ ele.project_id }}</td> <td><a href="/harbor_repositories/{{ ele.project_id }}"> {{ ele.name }}</a></td> <td>{{ ele.repo_count }} </td> <td><a href="/del_harbor_project/{{ ele.project_id }}"> 革除 </a></td> </tr> {% endfor %} </tbody> </table> </div></body></html>harbor_repositories.html<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title></head><body> <script src="/static/jquery-1.9.1.min.js"></script> <script> $('#out').click(function () { $.ajax({ url: '/dns_list/', type: 'GET', data: {}, success: function (data) { //期待解决完结主动调用,data-返回值 console.log(data); window.location.href = "url" } }) }); $('#back').click(function () { $.ajax({ url: '/dns_list/', type: 'GET', data: {}, success: function (data) { window.location.href = "/" } }) });function getValues_del_repositories() { var valArr=[]; var ones=document.getElementsByName('item'); for (var i=0;i<ones.length;i++){ if (ones[i].checked==true){ valArr[i]=ones[i].value } } if (valArr.length!=0){ // var vals = valArr.join(','); // alert(valArr); // var url2 = '/app_intstall/' $.ajax({ url:"/del_harbor_repositories_list/", type:'POST', contenType:'application/json',// #不加这个,ajax会将后果后边加个[],例如{'vals[]':[4,6,8]} traditional:true,// #不加这个,会报服务器终止了一个在运行的程序 async: false, data:{ 'vals':valArr }, success:function(){ alert("批量革除image 超过10个 tag 胜利"); // window.location.href =url2 }, error:function(){ alert("批量革除image 超过10个 tag 失败"); } }) } else { var error_m="请抉择数据"; alert(error_m); }} </script> <div class="container" style="position: absolute;left: -2%;width: 1590px;height: 850px;margin-left: 95px;display:block;overflow-y:auto;"> <h2>harbor</h2> {# <div style="position: absolute;top: 12%;left: 65%;width: 590px;height: 650px;">#} {# <p>text: <textarea rows="41" cols="80" name="conftext"> {{ conflook.conflook }} </textarea></p>#} {# </div>#} <table class="table table-condensed" id="table1" > <thead> <tr> <th width="25"><input id="checkAll" onclick="checkAll()" type="checkbox"></th> <th>我的项目</th> <th>标签数</th> <th>操作</th> </tr> </thead> <tbody> {% for ele in harbor_project1 %} <tr> <td><input name="item" onclick="checkOne()" type="checkbox" value="{{ele.name}}"></td> <td> {{ ele.name }}</td> <td>{{ ele.tags_count }} </td> <td><a href="/del_repositories_url/{{ ele.project_id }}/{{ ele.name }}"> 革除 </a></td> </tr> {% endfor %} </tbody> </table> </div></body></html>

April 27, 2021 · 5 min · jiezi

关于flask:flask-web-实现文件上传-下载-浏览-编辑

性能展现 代码展现app.ypfrom flask import Flask, request, render_template, redirect, url_for, make_response ,escape, session, flash, g, current_app, abort, jsonify, send_fileimport requestsfrom werkzeug.utils import secure_filenameimport os,time, platformfrom flask_wtf import Formfrom wtforms import TextFieldfrom shell import os_scrpict, harborimport sqlite3from pathlib import Pathfrom flask_sqlalchemy import SQLAlchemyapp = Flask(__name__)#app.pyapp.secret_key = 'development key'app.config['UPLOAD_FOLDER'] = 'upload/'filepath = Path('upload/')@app.route('/upload')def upload_file(): return render_template('dir_view.html')@app.route('/uploader', methods = ['GET', 'POST'])@app.route('/uploader/<path:filepath>/', methods = ['GET', 'POST'])def uploader(filepath=' '): if request.method == 'POST': repath = 'upload/' + filepath + '/' print(repath) f = request.files['file'] #f.save(os.path.join(app.config['UPLOAD_FOLDER'],secure_filename(f.filename))) f.save(os.path.join(repath, secure_filename(f.filename))) #return 'file uploaded successfully' return redirect('/scan/{tfilepath}'.format(tfilepath = filepath))@app.route('/download/<path:fullname>', )def download_file(fullname): #current_app.logger.debug(fullname) print(fullname) return send_file(fullname)@app.route('/look/<path:fullname>', )def look_file(fullname): f = open(fullname, encoding='UTF-8') resp = make_response(f.read()) #resp = make_response(open(fullname, encoding='UTF-8').read()) resp.headers["Content-type"] = "application/json;charset=UTF-8" # f = open(fullname, "r+",encoding='UTF-8',newline="\n") # str = f.read() # fullname1 = str(fullname).replace('\\', '/') # with open(fullname, "r+",encoding='UTF-8',newline="\n") as f: # 默认模式为‘r',只读模式 # contents = f.read() f.close() return resp@app.route('/scan/')@app.route('/scan/<path:ortherpath>/', )def index(ortherpath=''): file_ele_list = list() dir_ele_list = list() #for f in (Path('upload/'+ ortherpath).iterdir()): for f in (Path('upload') / Path(ortherpath)).iterdir(): #for f in os_scrpict.allfile('upload/'): if f.is_file(): fullname = str(f).replace('\\', '/') file_ele_list.append({'is_dir': 0, 'filesize': os.path.getsize(f) / 1000, 'last_modify_time': time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(os.path.getmtime(fullname))), 'look_url': url_for('look_file', fullname=fullname), 'download_url': url_for('download_file', fullname = fullname), 'fullname': fullname}) if f.is_dir(): fullname = str(f).replace('\\', '/') dirname = fullname.split('/') dir_ele_list.append({'is_dir': 1, 'filesize': 0, 'last_modify_time': time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(os.path.getmtime(fullname))), 'look_url': url_for('look_file', fullname = dirname[1]), 'download_url': url_for('index', ortherpath = dirname[1]), 'fullname': fullname}) #print(dirname[1],"########",dir_ele_list) #print(fullname,"fullname####",fullname[1:]) print(dir_ele_list + file_ele_list) repath = request.path.split('scan') print(request.path,"#############request.path##########",repath[1]) if 'look' in request.path: look_file1 = request.path.split('look/') return render_template('dir_view.html', ele_list=dir_ele_list + file_ele_list,path1 = {"path1": repath[1]},conflook = {"conflook": look_file(look_file1[1])}) else: return render_template('dir_view.html', ele_list=dir_ele_list + file_ele_list, path1={"path1": repath[1]}, conflook = {"conflook": "hello kugou"})@app.route('/get_configfile/<path:configname>', )def get_configfile(configname): print(configname) f = open(configname, "r+",encoding='UTF-8',newline="\n") str = f.read() f.close() return render_template('get_configfile.html', conflook = {"conflook": str,"configname": configname})@app.route('/edit_configfile/<path:configname>/', methods = ['GET', 'POST'])def edit_configfile(configname): if request.method == 'POST': fileconfig = request.form.get('conftext') print(configname) print(fileconfig) f = open(configname, 'w', encoding='utf8') # 写入文件内容 f.write(fileconfig) f.close() return redirect('/scan/')if __name__ == '__main__': app.run() #app.run(host="172.16.117.33",port=5888)dir_view.html<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title></head><body><div class="container" style="position: absolute;left: -2%;width: 1590px;height: 850px;margin-left: 95px;display:block;overflow-y:auto;"> <div style="width: 590px;height: 80px;"> <form action="http://localhost:5000/uploader{{ path1.path1 }}" method="POST" enctype="multipart/form-data"> <input type="file" name="file" accept="*.*"/> <input type="submit"/> </form> </div> <div style="float: left; width:938px;height:70px"><a> dir_path : {{ path1.path1 }} </a></div> <table class="table table-condensed" id="table1"> <thead> <tr> <th>名称</th> <th>最初批改工夫</th> <th>文件大小</th> <th>下载文件</th> <th>操作</th> </tr> </thead> <tbody> {% for ele in ele_list %} {% if ele.is_dir %} <tr class="warning"> <td><a> 目录 {{ ele.fullname }}</a></td> <td>{{ ele.last_modify_time }}</td> <td>{{ ele.filesize }} M</td> <td><a href="{{ ele.download_url }}"> 进入 {{ ele.fullname }}</a></td> <td><a href="{{ ele.download_url }}"> 关上目录 </a></td> {% else %} <tr class="success"> <td><a href="{{ ele.look_url }}"> {{ ele.fullname }}</a></td> <td>{{ ele.last_modify_time }}</td> <td>{{ ele.filesize }} Kb</td> <td><a href="{{ ele.download_url }}" download={{ ele.fullname }}>下载 {{ ele.fullname }}</a></td> <td> <a href="/get_configfile/{{ ele.fullname }}"><font size="2" face="arial" color="blue"> <i class="fa fa-pencil" aria-hidden="true"></i> 编辑</font></a> </td> {% endif %} {# <td><a href="{{ ele.look_url }}" >预览 {{ ele.fullname }}</a></td>#} {# <td>{{ ele.last_modify_time }}</td>#} {# <td>{{ ele.filesize }} M</td>#} {# <td><a href="{{ ele.download_url }}" download={{ ele.fullname }}>下载 {{ ele.fullname }}</a></td>#} </tr> {% endfor %} </tbody> </table></div></body></html>get_configfile.html<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title></head><body> <h2>Nginx_config</h2> <form method="POST" action="/edit_configfile/{{ conflook.configname }}"> <div style="position: absolute;left: 4%;width: 690px;height: 850px;"> <p> nginx_config-text: <textarea rows="35" cols="120" name="conftext"> {{ conflook.conflook }} </textarea> </p> </div> <div style="position: absolute;top: 800px;left: 77%;width: 150px;height: 150px;" "> <input type="submit" value="提交"/> <a href="/scan/"><font size="2" face="arial" color="blue" class="btn btn-default"> <i class="fa fa-pencil" aria-hidden="true"></i> home </font></a> </div> </form></body></html>款式 模板 写的有点糙,就不给你们了

April 27, 2021 · 3 min · jiezi

关于flask:Flutter-文本框初始化是显示默认值

刚开始做Flutter文本框时候,应用的是TextField。仿佛大多数状况下都没有问题。代码模式如下: class _FooState extends State<Foo> { TextEditingController _controller; @override void initState() { super.initState(); _controller = new TextEditingController(text: '初始化内容'); } @override Widget build(BuildContext context) { return new Column( children: <Widget>[ new TextField( // 当TextField 第一次创立时,controller会蕴含初始值, // 当用户批改文本框内容时,会批改controller的值。 controller: _controller, ), new RaisedButton( onPressed: () { // 通过clear()能够清空controller的值。 _controller.clear(); }, child: new Text('清空'), ), ], ); }}问题1:动态创建文本框初始值个别状况下,间接应用这种形式,没有任何问题。然而当初有一种状况: 问题1: 当页面文本框中的初始值是动静的,从后盾获取到的时候,应该怎么办呢?这种状况下,阐明创立TextEditingController时,并不知道文本内容。这个时候如果动静批改controller的话,会报错,基本没法应用。 这种状况我基本没遇到过,然而我感觉Flutter必定有解决办法。所以我去找了一下Flutter的文档,总算是没有白找,找到了一个(https://api.flutter.dev/flutt...[组件] TextFormField。 文档中有一句: If a controller is not specified, initialValue can be used to give the automatically generated controller an initial value.意思就是说,当不指定controller时,initialValue 就能够主动生成controller的初始值。 ...

March 15, 2021 · 1 min · jiezi

关于flask:一寸宕机一寸血十万容器十万兵Win10Mac系统下基于k8s搭建GunicornFlask高可用Web集群

原文转载自「刘悦的技术博客」https://v3u.cn/a_id_185 2021年,君不言容器技术则已,欲言容器则必称Docker,毫无疑问,它是当今最风行的容器技术之一,然而当咱们面对海量的镜像与容器时,怎么疾速精准的对海量容器进行治理和编排就又成了新的课题,此时,由Google开源的Kubernetes(读音[kub'netis],业界也有称其k8s的,但k8s其实就是文盲版的Kubernetes,只是因为k和s之间有8个字母)就应时而生了,它是一个开源的用于多个主机虚构成一个云平台后进行容器资源管理和利用编排引擎,致力于让部署容器化利用简略并且高效,提供了利用的全生命周期治理,如利用部署,布局,更新,保护等机制。本次咱们尝试在Win10/Mac零碎下,利用Kubernetes部署Gunicorn+Flask高可用Web集群我的项目。 首先,Kubernetes基于Docker-desktop,所以下载Docker-desktop安装包:https://www.docker.com/produc... 这里咱们应用的就是Docker官网最新版3.1.0,外部集成的Kubernetes版本是1.19.3,在装置之前有两点要阐明下,如果是Windows用户,须要确保零碎版本为专业版: 第二,在专业版的根底上,开启零碎的Hyper-v虚拟化性能: 所以Windows用户想要对Kubernetes一亲芳泽的话,同时确保下面两点即可,而Mac用户则无特殊要求。 双击安装包进行装置,默认装置在C盘目录,胜利后,启动Docker-desktop,个别状况下,Docker很容易启动胜利,然而Kubernetes往往会卡在启动界面,这是因为一些学术问题导致无奈下载Kubernetes的依赖镜像,此时咱们须要另辟蹊径,采纳一些开源的三方库曲折帮咱们下载这些镜像,这里举荐这个开源我的项目:https://github.com/AliyunCont... 输出命令拉取我的项目: git clone https://github.com/AliyunContainerService/k8s-for-docker-desktop.git进入我的项目的目录内,而后查看本人的Kubernetes版本号,该我的项目默认拉取的就是1.19.3的依赖镜像,如果您装置的Kubernetes是老版本,须要自行切换版本进行拉取操作: 如Kubernetes版本为 v1.18.8, 请应用上面命令切换 v1.18.8 分支 git checkout v1.18.8 如Kubernetes版本为 v1.18.6, 请应用上面命令切换 v1.18.6 分支 git checkout v1.18.6 如Kubernetes版本为 v1.18.3, 请应用上面命令切换 v1.18.3 分支 git checkout v1.18.3 如Kubernetes版本为 v1.16.5, 请应用上面命令切换 v1.16.5 分支 git checkout v1.16.5 如Kubernetes版本为 v1.15.5, 请应用上面命令切换 v1.15.5 分支 git checkout v1.15.5 如Kubernetes版本为 v1.15.4, 请应用上面命令切换 v1.15.4 分支 git checkout v1.15.4 如Kubernetes版本为 v1.14.8, 请应用上面命令切换 v1.14.8 分支 git checkout v1.14.8 如Kubernetes版本为 v1.14.7, 请应用上面命令切换 v1.14.7 分支 git checkout v1.14.7 如Kubernetes版本为 v1.14.6, 请应用上面命令切换 v1.14.6 分支 git checkout v1.14.6 如Kubernetes版本为 v1.14.3, 请应用上面命令切换 v1.14.3 分支 git checkout v1.14.3 如Kubernetes版本为 v1.14.1, 请应用上面命令切换 v1.14.1 分支 git checkout v1.14.1 如Kubernetes版本为 v1.13.0, 请应用上面命令切换 v1.13.0 分支 git checkout v1.13.0 如Kubernetes版本为 v1.10.11, 请应用上面命令切换 v1.10.11 分支 git checkout v1.10.11随后,如果是Mac用户间接执行shell脚本: ...

February 4, 2021 · 3 min · jiezi

关于flask:FlaskAPScheduler详细配置使用附带API调用

谁再不提前告诉我,就间接复制我的文章而后发表,全家生孩子没屁眼。原文链接:https://segmentfault.com/a/11... 作者:SyntaxError 1.配置from App.tasks.DatabaseTask import send_ding_test # 我的工作函数from flask_apscheduler.auth import HTTPBasicAuthfrom apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStoreclass Config(object): JOBS = [ # interval定时执行(从start_date到end_date,距离20s,蕴含首尾) # func也能够写字符串模式,例如:'App.tasks.DatabaseTask:send_ding_test' { 'id': 'job2', 'func': send_ding_test, 'trigger': 'interval', 'start_date': '2021-01-27 13:31:00', 'end_date': '2021-01-27 13:33:00', 'seconds': 20, 'replace_existing': True # 从新执行程序时,会将jobStore中的工作替换掉 }, # date一次执行 { 'id': 'job1', 'func': send_ding_test, 'trigger': 'date', 'run_date': '2021-01-30 11:22:00', 'replace_existing': True }, # cron式定时调度,相似linux的crontab { 'id': 'job3', 'func': send_ding_test, 'trigger': 'cron', 'day_of_week': '0-6', 'month': '*', 'hour': '6', 'minute': '0', 'second': '0', 'replace_existing': True } ] # 存储定时工作(默认是存储在内存中) SCHEDULER_JOBSTORES = {'default':SQLAlchemyJobStore(url='mysql+pymysql://xxx/xx')} # 设置时区,时区不统一会导致定时工作的工夫谬误 SCHEDULER_TIMEZONE = 'Asia/Shanghai' # 肯定要开启API性能,这样才能够用api的形式去查看和批改定时工作 SCHEDULER_API_ENABLED = True # api前缀(默认是/scheduler) SCHEDULER_API_PREFIX = '/scheduler' # 配置容许执行定时工作的主机名 SCHEDULER_ALLOWED_HOSTS = ['*'] # auth验证。默认是敞开的, SCHEDULER_AUTH = HTTPBasicAuth() # 设置定时工作的执行器(默认是最大执行数量为10的线程池) SCHEDULER_EXECUTORS = {'default': {'type': 'threadpool', 'max_workers': 10}} # 另外flask-apscheduler内有日志记录器。name为apscheduler.scheduler和apscheduler.executors.default。如果须要保留日志,则须要对此日志记录器进行配置    ...

January 28, 2021 · 2 min · jiezi

关于flask:3Flask构建弹幕微电影网站安装mysql数据库及配置

【百度云搜寻,搜各种材料:http://www.lqkweb.com】【搜网盘,搜各种材料:http://www.swpan.cn】Flask 构建微电影视频网站已上线演示地址: http://movie.tbquan.cn 装置数据库连贯依赖包安装包flask-sqlalchemy pip install flask-sqlalchemypip listPackage Version---------------- -------Click 7.0Flask 1.0.2Flask-SQLAlchemy 2.3.2itsdangerous 0.24Jinja2 2.10MarkupSafe 1.0pip 18.1setuptools 40.4.3SQLAlchemy 1.2.12Werkzeug 0.14.1wheel 0.32.1中文文档 http://www.pythondoc.com/flas... 查看配置键: http://www.pythondoc.com/flas... 连贯格局 MySQL: mysql://username:password@localhost/mydatabase 创立mysql数据库下载mysqlhttps://dev.mysql.com/downloa... 这儿间接用的最新版8.0 MySQL Community Server 学习应用下载社区版就能够 装置mysql 关上开始菜单的MySQL 8.0 Command Line Client验证是否失常装置 Enter password: rootWelcome to the MySQL monitor. Commands end with ; or \g.Your MySQL connection id is 11Server version: 8.0.12 MySQL Community Server - GPLCopyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.Oracle is a registered trademark of Oracle Corporation and/or itsaffiliates. Other names may be trademarks of their respectiveowners.Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.mysql> \s--------------C:\Program Files\MySQL\MySQL Server 8.0\bin\mysql.exe Ver 8.0.12 for Win64 on x86_64 (MySQL Community Server - GPL)Connection id: 11Current database:Current user: root@localhostSSL: Cipher in use is DHE-RSA-AES128-GCM-SHA256Using delimiter: ;Server version: 8.0.12 MySQL Community Server - GPLProtocol version: 10Connection: localhost via TCP/IPServer characterset: utf8mb4Db characterset: utf8mb4Client characterset: gbkConn. characterset: gbkTCP port: 3306Uptime: 2 min 20 secThreads: 2 Questions: 23 Slow queries: 0 Opens: 147 Flush tables: 2 Open tables: 123 Queries per second avg: 0.164--------------如果cmd中mysql命令不论用,须要增加环境变量,在Path中增加C:\Program Files\MySQL\MySQL Server 8.0\bin\,也就是mysql的装置目录 ...

December 12, 2020 · 1 min · jiezi

关于flask:2Flask构建弹幕微电影网站使用蓝图构建项目目录

【百度云搜寻,搜各种材料:http://ww.bdyss.cn】【搜网盘,搜各种材料:http://www.swpan.cn】Flask 构建微电影视频网站已上线演示地址: http://movie.tbquan.cn 蓝图构建我的项目目录什么是蓝图一个利用中或者跨利用制作利用组件和反对通用的模式 蓝图的作用将不同的性能模块化构建大型利用优化我的项目构造加强可读性、易于保护构建办法·定义注册调用定义蓝图(app/admin/__init__.py) from flask import Blueprintadmin = Blueprint("admin", __name__)import views注册蓝图(app/__init__.py) from admin import admin as admin_blueprintapp.register_blueprint(admin_blueprint, url_prefix="/admin")调用蓝图(app/admin/views.py) from . import admin@admin.route("/")开始创立我的项目定义蓝图app/home/__init__.py from flask import Blueprinthome = Blueprint('home', __name__)import app.home.viewsapp/admin/__init__.py from flask import Blueprintadmin = Blueprint('admin', __name__)import app.admin.views调用蓝图定义视图 app/home/views.py from . import home@home.route("/")def index(): return "<h1 style='color:blue'>前台</h1>"app/admin/views.py from . import admin@admin.route("/")def index(): return "<h1 style='color:red'>后盾</h1>"注册蓝图app/__init__.py from flask import Flaskapp = Flask(__name__) # 实例化flaskapp.debug = True # 开启调试模式from app.home import home as home_blueprint # 导入from app.admin import admin as admin_blueprintapp.register_blueprint(home_blueprint)app.register_blueprint(admin_blueprint, url_prefix="/admin")运行服务编写入口脚本,使整个我的项目启动起来 ...

December 12, 2020 · 1 min · jiezi

关于flask:从零做网站开发基于Flask和JQuery实现表格管理平台

摘要:本文将为大家带来基于Flask框架和JQuery实现治理平台网站的开发性能。【写在后面】你要开发网站? 嗯。。 会Flask吗? 什么货色,没听过。。。 会JQuery吗? 是python的库吗 ? 那你会什么? 我会F12关上网站 好吧,那咱们来写个简略的表格治理平台。 基于Flask框架和JQuery实现治理平台网站的开发性能,我代码编写用了2天的工夫 ,从零开始写;又对具体实现流程,本人断断续续地整顿总结了近半个月。从自我感觉来说,整个过程和后果的实现都让我很称心。 【成果如下】 【第一步】理解Flask框架1、理解python 支流的web框架(1)Django:简略来说就是重武器,是最全能的开发框架,你想要的性能它都有;然而比拟沉重,适宜企业级的web开发; (2)Flask:属于web开发微框架,玲珑灵便,相干的第三方库丰盛,适宜开发小型web; (3)Tornado:天生异步,性能强悍,然而框架提供的性能少,须要开发者本人实现; 因而,本文代码实现次要是基于Flask实现的。 2、理解Flask框架(1)HelloWorld实现:简直所有的编程都是基于“hello world”实现的,因而也大抵讲下helloworld波及的内容。 from flask import Flaskapp = Flask(__name__)@app.route('/')def hello_world(): return "Hello world!"if name == '__main__': app.run()先申明一个Flask框架的对象,而后定义路由'/',即URL地址为 http://127.0.0.1:5000/;如果定义门路为‘/new’,那对应的拜访地址须要改为http://127.0.0.1:5000/new。另外,@app.route是个装璜器。 (2)如何实现具体IP地址或者端口的拜访呢?app.run(debug=True,host="x.x.x.x",port="1234") 通过对app.run()办法的参数定义,别离实现了调试性能,拜访URL变更为 http://x.x.x.x:1234 这里调试性能还是很好用的,岂但能够帮忙开发者从新加载网页,而且会打印具体的错误信息,帮助定位。 (3)如何在web上显示本人特定的html模板from flask import Flask,render_templateapp = Flask(__name__)@app.route('/')def hello_world(): return render_template('test.html') if name == '__main__': app.run()只须要导入render_template库,并且在函数返回时改成对应的办法即可。 不过 这 里要 留神,test.html必须保留在工程目录与下template文件下,否则会报错。(这是因为render_template办法定义时默认写了template门路 ) 【第二步】理解Sqlite3数据库web数据交互离不开后盾数据库的治理,本章节重点解释python自带的sqlite3数据库。相比拟于其余“正规”的数据库,如mongo、solr、MySQL等,sqlite3相当简略,属于轻量级的数据库。 1、sqlite3数据库的装置和创立 用pip命令能够下载安装sqlite3数据库 创立数据库: con = sqlite3.connect('material.db') 如果有数据库material.db,则进行连贯数据库的操作;如果没有此数据库,则先创立数据库再进行连贯; 2、创立数据表 label = ['ID','网络IP','地址','责任人','联系方式']content = ['1','10.10.10.10','杭州滨江','鹏哥','123456']def create(): ...

December 2, 2020 · 4 min · jiezi

关于flask:设计一个基于flask的高并发高可用的查询ip的http服务

结构设计基础架构为flask+gunicorn+负载平衡,负载平衡分为阿里云硬件负载平衡服务和软负载nginx。gunicorn应用supervisor进行治理。 应用nginx软件负载结构图 应用阿里云硬件负载平衡服务结构图 因为flask app须要在内存中保留ip树以及国家、省份、城市相干的字典,因而占用内存较高。gunicorn的1个worker须要占用300M内存,nginx的4个worker内存占用较小(不到100M),因而占用1.3G的内存(即须要一个2G内存的服务器)。当gunicorn任意一个节点挂断或者降级时,另外一个节点依然在应用,不会影响整体服务 <!--more--> ip数据库IP库(也叫IP地址数据库),是由业余技术人员通过长时间通过多种技术手段收集而来的,并且长期有业余人员进行更新、保护、补充。 ip数据库解析查问代码 基于二叉查找树实现 import structfrom socket import inet_aton, inet_ntoaimport osimport syssys.setrecursionlimit(1000000)_unpack_V = lambda b: struct.unpack("<L", b)_unpack_N = lambda b: struct.unpack(">L", b)_unpack_C = lambda b: struct.unpack("B", b)class IpTree: def __init__(self): self.ip_dict = {} self.country_codes = {} self.china_province_codes = {} self.china_city_codes = {} def load_country_codes(self, file_name): try: path = os.path.abspath(file_name) with open(path, "rb") as f: for line in f.readlines(): data = line.split('\t') self.country_codes[data[0]] = data[1] # print self.country_codes except Exception as ex: print "cannot open file %s: %s" % (file, ex) print ex.message exit(0) def load_china_province_codes(self, file_name): try: path = os.path.abspath(file_name) with open(path, "rb") as f: for line in f.readlines(): data = line.split('\t') provinces = data[2].split('\r') self.china_province_codes[provinces[0]] = data[0] # print self.china_province_codes except Exception as ex: print "cannot open file %s: %s" % (file, ex) print ex.message exit(0) def load_china_city_codes(self, file_name): try: path = os.path.abspath(file_name) with open(path, "rb") as f: for line in f.readlines(): data = line.split('\t') cities = data[3].split('\r') self.china_city_codes[cities[0]] = data[0] except Exception as ex: print "cannot open file %s: %s" % (file, ex) print ex.message exit(0) def loadfile(self, file_name): try: ipdot0 = 254 path = os.path.abspath(file_name) with open(path, "rb") as f: local_binary0 = f.read() local_offset, = _unpack_N(local_binary0[:4]) local_binary = local_binary0[4:local_offset] # 256 nodes while ipdot0 >= 0: middle_ip = None middle_content = None lis = [] # offset begin_offset = ipdot0 * 4 end_offset = (ipdot0 + 1) * 4 # index start_index, = _unpack_V(local_binary[begin_offset:begin_offset + 4]) start_index = start_index * 8 + 1024 end_index, = _unpack_V(local_binary[end_offset:end_offset + 4]) end_index = end_index * 8 + 1024 while start_index < end_index: content_offset, = _unpack_V(local_binary[start_index + 4: start_index + 7] + chr(0).encode('utf-8')) content_length, = _unpack_C(local_binary[start_index + 7]) content_offset = local_offset + content_offset - 1024 content = local_binary0[content_offset:content_offset + content_length] if middle_content != content and middle_content is not None: contents = middle_content.split('\t') lis.append((middle_ip, (contents[0], self.lookup_country_code(contents[0]), contents[1], self.lookup_china_province_code(contents[1]), contents[2], self.lookup_china_city_code(contents[2]), contents[3], contents[4]))) middle_content, = content, middle_ip = inet_ntoa(local_binary[start_index:start_index + 4]) start_index += 8 self.ip_dict[ipdot0] = self.generate_tree(lis) ipdot0 -= 1 except Exception as ex: print "cannot open file %s: %s" % (file, ex) print ex.message exit(0) def lookup_country(self, country_code): try: for item_country, item_country_code in self.country_codes.items(): if country_code == item_country_code: return item_country, item_country_code return 'None', 'None' except KeyError: return 'None', 'None' def lookup_country_code(self, country): try: return self.country_codes[country] except KeyError: return 'None' def lookup_china_province(self, province_code): try: for item_province, item_province_code, in self.china_province_codes.items(): if province_code == item_province_code: return item_province, item_province_code return 'None', 'None' except KeyError: return 'None', 'None' def lookup_china_province_code(self, province): try: return self.china_province_codes[province.encode('utf-8')] except KeyError: return 'None' def lookup_china_city(self, city_code): try: for item_city, item_city_code in self.china_city_codes.items(): if city_code == item_city_code: return item_city, item_city_code return 'None', 'None' except KeyError: return 'None', 'None' def lookup_china_city_code(self, city): try: return self.china_city_codes[city] except KeyError: return 'None' def lookup(self, ip): ipdot = ip.split('.') ipdot0 = int(ipdot[0]) if ipdot0 < 0 or ipdot0 > 255 or len(ipdot) != 4: return None try: d = self.ip_dict[int(ipdot[0])] except KeyError: return None if d is not None: return self.lookup1(inet_aton(ip), d) else: return None def lookup1(self, net_ip, (net_ip1, content, lefts, rights)): if net_ip < net_ip1: if lefts is None: return content else: return self.lookup1(net_ip, lefts) elif net_ip > net_ip1: if rights is None: return content else: return self.lookup1(net_ip, rights) else: return content def generate_tree(self, ip_list): length = len(ip_list) if length > 1: lefts = ip_list[:length / 2] rights = ip_list[length / 2:] (ip, content) = lefts[length / 2 - 1] return inet_aton(ip), content, self.generate_tree(lefts), self.generate_tree(rights) elif length == 1: (ip, content) = ip_list[0] return inet_aton(ip), content, None, None else: returnif __name__ == "__main__": import sys reload(sys) sys.setdefaultencoding('utf-8') ip_tree = IpTree() ip_tree.load_country_codes("doc/country_list.txt") ip_tree.load_china_province_codes("doc/china_province_code.txt") ip_tree.load_china_city_codes("doc/china_city_code.txt") ip_tree.loadfile("doc/mydata4vipday2.dat") print ip_tree.lookup('123.12.23.45')http申请提供ip查问服务的GET申请和POST申请 ...

November 11, 2020 · 7 min · jiezi

关于flask:如何做好DDoS防御F5给出四点建议

DDoS攻打是黑客手中的利器,是所有运维者的心头痛,也是任何公司听闻后都将大惊失色的弱小对手。DDoS全称Distributed Denial of Service,中文意思为“分布式拒绝服务”。是利用大量非法的分布式服务器对指标发送申请,从而导致服务器拥塞而无奈对外提供失常服务,只能发表game over。 从企业客户角度来看,DDoS进攻是一个漫长的过程,攻打伎俩和工具会一直刷新,那么如何如何做好DDoS进攻?F5给出四点倡议! 第一点倡议,用户须要意识到网络攻防和合规是两回事,平安部署不应该以合规为指标,而要重点思考攻防,将攻防搁置于首位。 第二点倡议,用户须要扭转对立安全策略,对于要害利用而言,须要对利用做完流量精分之后,再依据不同灰度的流量进行安全策略配置。F5产品+服务的攻防模型曾经被泛滥用户证实是无效的,可供参考。 第三点倡议,不要将平安防御能力全副寄希望于全自动平安模式,从另一个角度而言,全自动也意味着平安危险,最好的解决方法是要做可控的风险管理。 第四点倡议,审慎抉择通明模式和Bypass模式!很多客户被攻打就是因为这两个模式,现在的DDoS攻打终极目标其实并不是让业务瘫痪,而是为了在彻底打穿透明模式和Bypass模式之后,覆盖不法分子如入无人之境般窃取外围数据。对此F5给出的解决之道是构建一个超高弹性的全代理架构,做古代攻防的解决。 在F5的Advanced WAF(API 平安——新一代 WAF)+服务的框架下,通过大数据采集、机器学习、智能基线判断,最初进行预案全副工作都由F5实现,客户本人来判断是否通过“一键切换”进入进攻状态。“F5通过机器学习的办法来去判断失常流量、异样流量和用户行为,而后通过AIOps的形式去做解决,最初给客户一键选择权。 攻防是第一指标,流量精分是实现办法。F5心愿实现的成果是通过机器学习之后的一键操作,而不是简略的全自动,最终构建出残缺的DDoS进攻体系。 

October 10, 2020 · 1 min · jiezi

关于flask:Flask从零到一-2-flask相关参数配置

上一篇文章介绍了学习flask之前须要的筹备工作,也就是Git工具的下载和虚拟环境的配置,还介绍了如何编写一个最简略的flask程序,还捎带讲了一下有对于动态目录和模板目录的常识,这篇文章会深刻解说一下flask一些参数的配置。 app初始化参数上一篇文章咱们提及过在以后模块的根目录下会默认存在一个static,当然这是咱们不在网页加任何润饰的状况。但如果咱们须要将一些动态文件展现到网页中,咱们就须要创立一个static文件夹来保留这些动态文件,它应该与以后模块处于同级目录。 之前咱们通过拜访绑定的url调用相应的视图函数,从而将返回值传至客户端页面,咱们也能够通过拜访动态文件夹static中的html文件,间接将html文件中的内容展现在客户端,首先咱们须要做的就是在的static中创立一个html文件,内容能够依照本人的情意填写。 关上浏览器输出网址,门路须要是 根地址/static/.html 格局,这样就能够拜访对应的html文件。 但在咱们实例化app对象中,也能够设置一些初始化参数: 1、import_name:寻找动态目录和模板目录地位2、static_url_path:拜访动态文件时url的前缀3、static_folder:动态文件目录,默认为static4、template_floder:模板文件目录,默认为templatesimport_name参数如果传入__name__,就示意在以后模块目录中寻找动态和模板目录,当然也能够传入其余参数,但这里倡议用__name__。而第二个参数是用来自定义动态文件url前缀的,默认就为static,但如果咱们更改了app对象中的这个参数: app = Flask(__name__, static_url_path='/index')在拜访同一个动态文件时必须将url中的static更改为index,能力胜利拜访: 这个前缀也是比拟重要的,因为咱们之前说过通过视图函数也能够有同样的成果,这个前缀也是证实你在拜访一个动态文件,而不是一个视图函数。 而剩下两个参数不设置的话就会在以后模块目录下寻找名为static和templates的文件夹,而如果进行了设置,就会到你设置的目录下寻找对应的动态和模板目录。 debug参数配置咱们平时编程的时候应该都用过Debug性能调试代码,"万能的Debug一下",当咱们在写Flask程序时,如果代码局部呈现了谬误,运行之后客户端会给出一个很泛泛的谬误提醒,比方HTTP状态码。如果咱们在代码中加一个除零谬误,运行之后客户端的页面如下: 这样咱们只是晓得代码中有谬误,却不晓得错在哪,找BUG难上加难。而Flask中也是有DEBUG这个参数的,咱们须要做的就是对这个参数进行配置,办法大抵有以下四种: 1、通过配置文件2、通过对象配置3、间接在config字典中设置4、在run办法中设置办法一首先咱们在文件的同级目录下创立一个名为 config.cfg 的文件,并在文件中增加上面这行语句: DEBUG = True而后回到代码文件中,通过在app对象上进行配置,代码如下: app.config.from_pyfile('config.cfg')办法二因为Python中所有皆对象,类也是一个对象,所以咱们能够通过创立一个类,而后将DEBUG设置为这个类中的一个属性: class Config(): DEBUG = True而后也是在app对象上进行配置,只不过从文件配置改成从对象配置: app.config.from_object(Config)办法三app利用对象中的config能够了解成一个字典对象,咱们也能够间接在这个字典上进行配置debug参数: app.config["DEBUG"] = True须要留神的是配置大量参数能够应用这种办法,而参数过多则会导致代码量多,写起来简单,代码可读性也会升高。 对于config这个字典对象,咱们也能够依据配置参数中已知的键来查问对应的值: print(app.config.get("已知键"))办法四第四种办法应该是最简略的,run()办法的作用就是运行flask程序,外面也有一个debug参数,默认为False,当咱们设置为True时,Debug性能开启: app.run(debug=True)run()办法中也有一些其余参数可供配置,比方主门路、端口号等等,这里不再过多介绍,有须要的搭档能够查问官网文档。 这四种办法咱们任选其一配置好DEBUG参数后,再次运行程序,Pycharm运行栏里的信息通知咱们DEBUG性能曾经开启: 而后回到浏览器刷新页面,会发现客户端会给出了精确的代码谬误,通知你这是一个除零谬误,所以咱们只须要去找无关代码即可: 综上为本文全部内容,次要介绍了flask程序中两个比拟重要的参数:app利用对象的初始参数和debug参数,以及四种配置debug参数的根本办法。 本文参考资料:[1].《Flask入门教程》.李辉著[2].https://www.bilibili.com/vide...[3].Flask中英文档如果你对这个系列感兴趣,欢送关注公众号【奶糖猫】第一工夫跟进后续更新~

August 14, 2020 · 1 min · jiezi

关于flask:flaskpython-实时视频流输出到前台

问题形容: 1。调用摄像头获取视频流 2。将视频流解决并传递给浏览器 3。不是录制后处理,而是边录制边解决,边传递 4。 flash后盾进行解决,而不是在前端解决 问题解决: 办法起源:外汇名词解释https://www.fx61.com/definitions server.py from flask import Flask, render_template, Responseimport cv2 class VideoCamera(object): def __init__(self): # 通过opencv获取实时视频流 self.video = cv2.VideoCapture(0) def __del__(self): self.video.release() def get_frame(self): success, image = self.video.read() # 在这里解决视频帧 cv2.putText(image, "hello",(10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.8,(0, 255, 0)) # 因为opencv读取的图片并非jpeg格局,因而要用motion JPEG模式须要先将图片转码成jpg格局图片 ret, jpeg = cv2.imencode('.jpg', image) return jpeg.tobytes() app = Flask(__name__,static_folder='./static') @app.route('/') # 主页def index(): # jinja2模板,具体格局保留在index.html文件中 return render_template('index.html') def gen(camera): while True: frame = camera.get_frame() # 应用generator函数输入视频流, 每次申请输入的content类型是image/jpeg yield (b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n') @app.route('/video_feed') # 这个地址返回视频流响应def video_feed(): return Response(gen(VideoCamera()), mimetype='multipart/x-mixed-replace; boundary=frame') if __name__ == '__main__': app.run(host='0.0.0.0', debug=True, port=5000) index.html ...

August 12, 2020 · 1 min · jiezi

关于flask:flaskpython-实时视频流输出到前台

问题形容: 1。调用摄像头获取视频流 2。将视频流解决并传递给浏览器 3。不是录制后处理,而是边录制边解决,边传递 4。 flash后盾进行解决,而不是在前端解决 问题解决: 办法起源:外汇名词解释https://www.fx61.com/definitions server.py from flask import Flask, render_template, Responseimport cv2 class VideoCamera(object): def __init__(self): # 通过opencv获取实时视频流 self.video = cv2.VideoCapture(0) def __del__(self): self.video.release() def get_frame(self): success, image = self.video.read() # 在这里解决视频帧 cv2.putText(image, "hello",(10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.8,(0, 255, 0)) # 因为opencv读取的图片并非jpeg格局,因而要用motion JPEG模式须要先将图片转码成jpg格局图片 ret, jpeg = cv2.imencode('.jpg', image) return jpeg.tobytes() app = Flask(__name__,static_folder='./static') @app.route('/') # 主页def index(): # jinja2模板,具体格局保留在index.html文件中 return render_template('index.html') def gen(camera): while True: frame = camera.get_frame() # 应用generator函数输入视频流, 每次申请输入的content类型是image/jpeg yield (b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n') @app.route('/video_feed') # 这个地址返回视频流响应def video_feed(): return Response(gen(VideoCamera()), mimetype='multipart/x-mixed-replace; boundary=frame') if __name__ == '__main__': app.run(host='0.0.0.0', debug=True, port=5000) index.html ...

August 12, 2020 · 1 min · jiezi

关于flask:Flask从零到一-1-虚拟环境和第一个flask程序

大概还有二十天假期工夫,这二十天我筹备跟进一个Flask入门系列,大抵会分为10-12篇文章。尽管我当前不想做开发,然而Web开发热度还是挺高的,所以就用了一段时间学习了一下,下学期也会有与Web无关的课程,如果对Flask感兴趣的话,能够继续跟进,心愿这个系列能够帮到搭档们。 第一篇次要包含两个方面,一方面是学习Flask之前的筹备工作,比方配置相应的环境以及下载一些工具;另一方面就是编写第一个Flask简易程序。 Flask是反对Python2 和 Python3两个版本的,然而在我接触Python的时候曾经更新到3.6了,所以我也没有关注Python2。我置信搭档们应该也大多都在用Python3,所以这个系列会以Python3为根底,Flask的版本应用最新的即可。 这里只对Flask做一个简要的介绍:Flask是一个微框架,自身相当于一个内核,只保留了外围性能:申请响应解决和模板渲染。这两个性能别离有Werkzeug和Jinja实现,Flask自身也包装了这两个依赖,而后Flask还领有很多扩大包,用户能够依据本人的需要导入扩大包实现相应的性能,这也是Flask框架灵便的起因。 Git下载首先对于Windows用户,举荐下载Git这个工具,尽管很多性能咱们在终端也能够实现,但在某些方面上讲应用Git的命令会更加不便,而且它也能够用来记录编写程序的源码和文件的变动状况,Git的下载安装教程能够参考这篇博客:Windows零碎装置教程。 下载安装实现之后,在搜寻栏找到Git Bash,运行时候输出git --version,如果呈现对应的版本信息则代表装置胜利。 配置虚拟环境虚拟环境是一种独立于Python全局环境的Python解释器环境,比方一个虚拟环境中的解释器版本能够为Python2,另一个的解释器版本能够为Python3,它们之间是不会互相烦扰的,而且也不会受你电脑中Python环境的影响。 配置虚拟环境是很必要的操作,因为不同的程序依赖语言的版本可能会不同,但如果在一台电脑中下载多个版本Python解释器,就会导致全局环境芜杂,虚拟环境很好的解决了这个问题,也便于管理咱们的程序。 Python3中内置的venv模块能够创立虚拟环境,首先在零碎自带的cmd中通过cd指令进入到指定的文件中,须要留神的是这个门路不能蕴含中文,而后应用上面指令创立一个虚拟环境。 python -m venv env 其中env为虚拟环境的名称,能够本人拟定。这时会在当前目录下生成一个蕴含了Python解释器的虚拟环境文件夹,而后在Scripts文件下有两个.bat文件,这两个文件就管制着激活虚拟环境和退出虚拟环境。 通过上面指令就能够激活虚拟环境和退出虚拟环境: env\Scripts\activate#激活env\Scripts\deactivate#退出或者也能够间接进入Scripts目录下间接输出activate或者deactivae即可,当目录前呈现上面这种小括号模式就代表激活虚拟环境胜利。 (env) 而后就能够通过pip在虚拟环境中装置Flask,不必指定版本,默认装置最新版本。 pip install flask第一个flask程序编写一个flask程序是非常简单的,仅仅几行代码就能够实现,流程大抵能够分为以下五步: 1、从flask包中导入Flask类2、实例化Flask类,创立一个利用对象3、定义视图函数4、为视图函数增加装璜器(定义路由)5、启动flask程序#从flask包中导入Flask类from flask import Flask#创立flask的利用对象app = Flask(__name__)@app.route('/')def hello(): """定义视图函数""" return 'Hello NaiTangMao'if __name__ == "__main__": #启动flask程序 app.run()运行下面这段程序会给出上面的后果,咱们先关注红字局部的网址,会发现这是咱们本地主机的IP地址,在运行一个flask程序后,他会默认监听主机的5000端口。 Copy一下网址利用浏览器关上就会呈现咱们视图函数中返回的信息: 这个flask程序处理过程如下: 1、首先用户启动程序,并拜访对应的网址。2、服务器解析申请,辨认装璜器中绑定的URL。3、匹配URL并调用对应的视图函数。4、获取视图函数的返回值,返回至客户端。对于下面这几行代码须要把握几个知识点,首先你应该明确app为Flask类实例化后创立的一个利用对象,但外面的__name__有什么作用呢? __name__为以后模块名,因为flask程序在运行的时候须要动态文件和模板文件辅助,在你设置__name__之后,flask就会以以后模块(文件)所在目录为根目录,默认这个目录中的static为动态目录,templates为模板目录,因为是默认存在的,所以在根目录中并不会体现进去。不了解不要紧,前面还会波及这两方面常识。 视图函数临时不须要过多介绍,须要留神的是视图下面的装璜器app.route(),这个装璜器能够为视图函数绑定一个URL,当用户拜访这个URL时会触发对应的视图函数,其中'/'代表根地址,咱们还能够在根地址后设置额定门路,比方app.route('/hello')。 这时如果咱们在拜访原来那个网址就会呈现Not Found的谬误提醒,此时必须要拜访http://127.0.0.1:5000/hello能力触发视图函数。一个视图函数也能够同时绑定多个URL,这通过为视图函数增加多个装璜器实现: @app.route('/')@app.route('/hello')def hello(): """定义视图函数""" return 'Hello NaiTangMao'也就是说当初不管咱们拜访http://127.0.0.1:5000/ 还是 http://127.0.0.1:5000/hello都能够触发这个视图函数。 综上为Flask入门系列的第一篇,次要介绍虚拟环境的配置以及繁难flask程序形成局部的简要解析。 本文参考资料:[1].《Flask入门教程》.李辉著[2].https://www.bilibili.com/vide...[3].Flask中英文档如果你对这个系列感兴趣,欢送关注公众号【奶糖猫】第一工夫跟进后续更新~

August 6, 2020 · 1 min · jiezi

关于flask:Fastjson到了说再见的时候了

生命太短暂,不要去做一些基本没有人想要的货色。本文已被 https://www.yourbatman.cn 收录,外面一并有Spring技术栈、MyBatis、JVM、中间件等小而美的专栏供以收费学习。关注公众号【BAT的乌托邦】一一击破,深刻把握,回绝浅尝辄止。 前言各位小伙伴大家好,我是A哥。停更1个月后回归啦,明天咱们聊聊一个比拟有意思的话题:是否真的须要跟Fastjson说再见了? 我的态度我在CSDN写过好些篇对于JSON的文章,特地是2020年专门写了一个付费专栏:享学Jackson这个专栏“销量”在我心目中还对付,4个月“卖出”200份的样子(虽不值一提,但我很满足了????),小小的一个JSON库而已,热度可见一斑。专栏里不可避免的提到了Jackson和Fastjson的比拟,我自己始终持中立态度,次要起因有二: 两者都很风行(国内Fastjson风行度甚至超过Jackson),因而平时开发中我两者都用(须要随大流嘛)国产开源软件是须要被反对的,即便当初还存在差距(联想下最后的国产手机和苹果手机的差距,再看看当初呢?)当然,本文不一样了,必须得加点料。态度中立并不代表没有偏差:很显著我偏差于应用Jackson作为你的 惟一 JSON库。 从本文起,我将把CSDN里该付费专栏全部内容搬到公众号,收费助你轻松拥抱世界上最好的JSON库:Jackson。从本文起,我将把CSDN里该付费专栏全部内容搬到公众号,收费助你轻松拥抱世界上最好的JSON库:Jackson。从本文起,我将把CSDN里该付费专栏全部内容搬到公众号,收费助你轻松拥抱世界上最好的JSON库:Jackson。 市面上并无成体系介绍Jackson的教程(官网都木有),独此一家哦。当然喽,这必将伤害到我的CSDN专栏售卖权利(小钱也是钱嘛????),所以心愿你关注公众号,关注此专栏,而后学到手我就感觉值了2020-05-30阿里云应急响应核心监测到Fastjson暴发新的反序列化近程代码执行破绽,黑客利用破绽,可绕过autoType限度,间接近程执行任意命令攻打服务器,危险极大(话外音:此bug必须Fix)。侥幸的是,官网的响应速度十分快:还记得上一次Fastjson 高级别危险 安全漏洞是什么时候吗?是的,它就产生在2019-09-04,两次相距着实不远,不满你说我还历历在目呢,我司安全部门发的邮件还能找到????。 当然,之前也有些破绽问题,但关注度不如这两次。次要是这两次工夫相近,危险级别十分高影响面很大,所以社区反馈较为强烈这两次“相邻”的安全漏洞着实把Fastjson推到了风口浪尖,吃瓜大众一波接一波,一时间 “弃用Fastjson,拥抱Jackson/Gson” 的声音不绝于耳。这很容易了解,因为谁都不愿意时不时收到公司安全部门的这种邮件:针对此破绽,虽说咱们Fix起来步骤简略:降级Fastjson的版本,而后重启利用。看起来毫不费力,实则是个大坑。你是否曾想过这个问题:假使有上百个、几百个Java利用呢?且不谈你操作上的工夫和人力老本有多高,单单治理起来的工作量也不容小觑。所以如果你是技术Leader,胸中的怒火开释一下是在情理之中的。 置信很少有部门/团队把Spring Boot利用做成Jar包拆散的模式的吧~因而大概率都须要通过升版本 -> 提交代码 -> 合代码 -> 上pre -> 上线 -> 验证等步骤,so还是比拟麻烦的你为何用Fastjson?这个问题你能够问本人,也能够问身边的共事。汇总一下就是答案,这才是来自用户最实在的声音嘛。我针对此也简略“考察”过,把我听到的理解到的汇总为如下三点: API简略(static办法间接应用),上手快,对开发者敌对阿里巴巴出品,背靠大厂值得信赖.社区绝对沉闷,保护降级有保障容我猜猜,这3个理由大概率命中了你心中所想吧?????有大厂做背书天然能给产品加分,但本身优良才是硬道理。尽管起因有三点,但我认为让很多人决定去应用它、赞它的最最最次要起因其实就一点:API简略,static办法间接调用对开发者敌对。 我感觉对于大多数Java Coder(特地对于初学者)来说,应用时会有这样的一种情节在外面:静态方法的逼格比实例办法高。而实际上不应该是这样子的,初学者(初/中级选手)酷爱应用静态方法,而高手在设计一个库/框架时应在静态方法+实例办法间运用自如。一味地、过多地应用静态方法只会让你的的思维偏向于面向过程,而非更好的利用Java 面向对象 的个性,因而高下立判。 没有孰优孰劣,适宜的才是最好的发现了没,应用Fastjson的起因中,咱们至始至终都没有提到性能高/速度快等字眼,但这却是Fastjson最最最为外围的个性,堪称是它能立足于泛滥JSON库中、“怀才不遇”的立身之本。岂不怪哉,咱们应用它竟不是因为它最外围的个性有多好,那这是为何呢? 你为何仍在用Fastjson?起因能够说出5678种,总而言之言而总之,你不(敢)切换的起因或者只有一个:Fastjson的静态方法调用用着省心;最重要的是,对其它JSON库(如Jackson/Gson)并不相熟不敢切换。 我认为胆怯来自于未知不可否认Jackson/Gson的应用门槛确实比Fastjson高那么一丢丢,但这绝不是你回绝去应用它的理由。受Fastjson这“间断”两次高危破绽影响,A哥更加动摇了把Jackson当作 惟一 JSON库的信心,甚至在团队内严令禁止应用Fastjson。大家对立了语言/工具,更能进步生产力~ 如果你也是因为不太理解Jackson而不敢来到温室,那么看到本文就很侥幸了,本系列会收费带你拥抱Jackson这个高级JSON库,性能上比Fastjson强了不止一点点。 注释坊间在某坛里看到这样一句舆论:若你还依赖于应用Fastjson,那么你大概率还只是初/中级程度。这句话必然让Fastjson的忠诚用户火冒三丈,抄起家伙嘎嘎就是干。话出必然有因,那么这句话是否真的言过于词呢?接下来就絮叨絮叨 我很违心用存在即正当准则来表白一个观点:Fastjson出个bug就能有这么高的关注度,不可否认这自身就是一种胜利。 误区形容:“正当”请不要误读为“合乎情理”之类,而是当做“理由”来讲。“存在即正当”正确理解为:所有存在的事物都有它存在的理由任何技术可能流行起来,well-known被咱们所熟知必然有它的劣势,哪怕这个过人之处只有一个。上面咱们来看看为何Fastjson能一步步被钟爱,它的魔力到底在哪? 技术选型不应该像相亲:必定你只须要一个理由,而否定你却能... Why Fastjson?尽管最近Fastjson因为呈现安全漏洞,社区舆论一边倒。即使如此,简直没人间接否定过Fastjson自身的优良,特地是当你晓得这个应用宽泛的库简直全副来自于一人之手时。他就是匠人温少: 值得一提的是:温少另一个开源我的项目Druid是国内最风行的(甚至没有之一)数据库连接池产品,广受好评成人只看利弊,小孩才分对错。为何要应用它能风行开来,那必然是因为它优良。它优秀品质在其官网可一览无遗:这些“长处”用中文形容进去更加直(震)观(撼): 1、速度快fastjson绝对其余JSON库的特点是快,从2011年fastjson公布1.1.x版本之后,其性能从未被其余Java实现的JSON库超过。 话外音:速度/性能这一块,Fastjson始终拿捏得死死的 2、应用宽泛fastjson在阿里巴巴大规模应用,在数万台服务器上部署,fastjson在业界被宽泛承受。在2012年被开源中国评比为最受欢迎的国产开源软件之一。 话外音:阿里巴巴数以万计的大规模集群实例做规模背书,说服力杠杠的 3、测试齐备fastjson有十分多的testcase,在1.2.11版本中,testcase超过3321个。每次公布都会进行回归测试,保证质量稳固。 话外音:单测覆盖率高,代码健壮性有保障 4、应用简略fastjson的API非常简洁。 String text = JSON.toJSONString(obj); //序列化VO vo = JSON.parseObject("{...}", VO.class); //反序列化话外音:不论你是小白还是小小白,轻松上手,应用起来都无障碍 5、性能齐备反对泛型,反对流解决超大文本,反对枚举,反对序列化和反序列化扩大。 话外音:我这一家就够了,你要的,这都有 Why Not Fastjson?文首有表态本文我是有态度和有偏差的,因而不来几点起因实则不妥。那么我就针对于官网列出的5点(见上),给出个人观点供以参考。是否言过于辞,咱们拿出另外一个JSON库做出比照,本文以Jackson为例。 ...

July 20, 2020 · 1 min · jiezi

FlaskSocketIO部署遇到的问题

我的情况是服务端用Flask,前端用Vue.js。问题都出在Flask上。 CORS跨域问题这个问题令我很不愉快,是因为写法的问题导致的。实际上我在实例化SocketIO时已经传入cors_allowed_origins的参数为*,但是最后的问题出在*要用单引号,不能用双引号。我觉得这可能是前后传参符号不一致导致的,应该不是必须要求写单引号。 # 错误的写法socketio = SocketIO(app, cors_allowed_origins="*", async_mode='eventlet')# 正确的写法socketio = SocketIO(app, cors_allowed_origins='*', async_mode='eventlet')400错误这个需要配置Nginx,参考了一篇帖子,配置如下 location /{ proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";}其中第一行是告诉nginx使用HTTP/1.1通信协议,这是websoket必须要使用的协议。 第二行和第三行告诉nginx,当它想要使用WebSocket时,响应http升级请求。 参考资料:400错误解决方法400错误官方issue

June 21, 2020 · 1 min · jiezi

Flask项目中用户密码登陆跳转页面

在功能文件夹中注册蓝图,使用render_template包进行渲染页面 渲染路径与存放路径一致 一定要导入蓝图使用,要不然无法启动 **启动flask项目访问 ..../user/login就会渲染进入到login.html页面当中。** 现在想输入登陆用户名与密码并进行跳转到指定的页面。 现在点击登陆看怎么获取用户名和密码 注意前端用户名和密码的命名规范,一定保持一致。 输入用户名密码,点击登陆查看是否能获取到数据 成功获取到数据 一般项目中前端会去判断用户名密码是否正确或者为空。但是后端也要一定去判断,所有的用户输入的数据都是变化因素。要严谨的看待。 再试试不填写用户名或者密码时看看返回的json数据 在数据库当中增加用户名和密码,试试从数据库中对比数据进行验证返回。 添加测试数据 项目链接数据库 数据库字段表明构建 验证密码时,先对密码进行加密 导入User表以及加密文件 然后进行测试当用户名输入错误或者没填时会返回 当密码输入错误或者没输时返回 只有全部输入成功以及正确的时候,才能将用户名密码返回得到!

June 5, 2020 · 1 min · jiezi

建立Flask项目初始框架

在写flask项目的时候,框架配置尤为重要。大致框架思路如下: 在application.py中封装flask的类 manager.py中引入封装的类 在配置文件中,设置数据库配置,Debug配置,post配置等。 基本配置完成,可以在controllers文件夹中定义功能展示。基本展示页面的内容。 先注册蓝图 初始化导入蓝图使用 在Terminal中开启Flask项目python manager.py runserver配置文件中设置的端口号是多少,链接就会显示多少 成功显示页面内容!

June 4, 2020 · 1 min · jiezi

Flask实战从后台管理到人脸识别六款优质Flask开源项目介绍

Flask 是一个微型的 Python 开发的 Web 框架,基于 Werkzeug WSGI 工具箱和 Jinja2 模板引擎。 Flask 使用 BSD 授权。 Flask 也被称为 “microframework”,因为它使用简单的核心,用 extension 增加其他功能。Flask 没有默认使用的数据库、窗体验证工具。然而,Flask 保留了扩增的弹性,可以用 Flask-extension 加入这些功能:ORM、窗体验证工具、文件上传、各种开放式身份验证技术等。 今天为大家介绍的就是 Gitee 上六款优质的 Flask 项目,想要学习 Flask 的同学千万不要错过。 picbed项目作者:staugur 开源许可协议:BSD-3Clause 项目地址:https://gitee.com/staugur/picbed 基于Flask的Web自建图床,默认存储在本地,内置支持存储到又拍云、七牛云、阿里云OSS、腾讯云COS、GitHub、Gitee。 authbase项目作者:David 项目地址:https://gitee.com/zhujf21st/authbase 基于Python的Flask WEB框架实现后台权限管理系统,内容包含:用户管理、角色管理、资源管理和机构管理。前端页面参考了sypro。 PyFly项目作者:981764793 开源许可协议:MIT 项目地址:https://gitee.com/981764793/PyFly Flask + Layui Fly Template实现的一个社区项目,使用flask-admin实现了简单的后台管理功能,数据库使用Mongodb,前台实现功能:用户注册、登录、邮件激活、发帖、回帖、点赞、回复、采纳、删帖、结贴等功能。 easy-flask-json-mvc-socketio项目作者:水漫门廷 开源许可协议:Apache-2.0 项目地址:https://gitee.com/huashiyuting/flask 一套基于flask,vue的前后端分离的解决方案。 flask-ansible项目作者:shijiange 项目地址:https://gitee.com/shijiange/flask-ansible Flask实现Ansible和Ansible-Playbook的配置+部署系统。同时带有简单的服务器管理系统和认证系统。 face-recognition-service项目作者:westinyang 开源许可协议:Apache-2.0 项目地址:https://gitee.com/westinyang/face-recognition-service 使用 Face Recognition & Flask 构建的人脸比对服务,提供HTTP接口,Pyinstaller打包项目为可独立运行的exe程序。 ...

June 2, 2020 · 1 min · jiezi