Mac系统下Java开发环境搭建

开始学习Java了,先把运行环境搞起来.
写Java最流行的工具还是IntelliJ IDEA,因为也要看php代码顺道把PhpStorm给装上了,这两个都有了,也不差PyCharm了.

软件 版本 系统
IntelliJ IDEA 2020.2.3 Mac
PhpStorm 2020.2.3 Mac
PyCharm 2020.2.3 Mac

免责声明:软件和激活工具都来源于网络
我收集的是Mac系统的,Windows的,要自己找了,激活方法估计一样
激活后可用日期到2089年

微信公众号后台回复:31 获取百度地址

双击相应的dmg,拖到/Application即可

首先打开软件
勾选 Evaluate for free, 点击 Evaluate:

将jetbrains-agent.zip拖入 IDEA 界面中:

提示需要重启,点击Restart

启动后,需要输入激活参数

激活参数在:jetbrains-agent.txt里
提示再次重启,

重启后,通过Help->Register查看Licenses


可以愉快的玩耍了.

Posted in Java | Tagged , , , , , , | Leave a comment

ELK|kafka增加及删除topic


书接上回,想在kafka执行命令,其实是为删除一个无用的topic,但是在不知道正确删除姿势的情况下,只能先创建,顺道练习了一下命令行调整分区数和副本数,也是去年的经验了,今年用的时候又翻半天,记录一下

创建topic

用的命令是kafka-topics.sh,我是在容器里运行的,应该是kafka命令都加到PATH路径了,可以任意位置执行
查看所有topic列表

kafka-topics.sh  --zookeeper 192.168.0.1:2181 -list

创建topic
此处创建了三个分区一个副本的主题,一般有几个节点最好创建整数倍的分区,副本话,我们是日志,因为是量很大,倒没考虑多个副本,毕竟1T的日志量,多存一份就是直接存储空间的翻倍,还是要根据实际情况来的.

bash-4.3# kafka-topics.sh --create \
--zookeeper 192.168.0.1:2181 \
--topic test-topic \
--partitions 3 \
--replication-factor 1
Created topic "test-topic".

查看指定topic

bash-4.3# kafka-topics.sh --describe \
--zookeeper 192.168.0.1:2181 \
--topic test-topic
Topic:test-topic        PartitionCount:3        ReplicationFactor:1     Configs:
        Topic: test-topic       Partition: 0    Leader: 3       Replicas: 3     Isr: 3
        Topic: test-topic       Partition: 1    Leader: 1       Replicas: 1     Isr: 1
        Topic: test-topic       Partition: 2    Leader: 2       Replicas: 2     Isr: 2

删除topic

删除的话,需要要在kafka和zookeeper同时操作,只操作kafka的话,通过kakfa-manager等工具查看时,topic还会存在

kafka-topics.sh --delete \
 --zookeeper 192.168.0.1:2181 \
 --topic test-topic

zk操作

cd /usr/lib/zookeeper/bin
zkCli.sh -server 127.0.0.1:2181
rmr /brokers/topics/test-topic

弄了一个微信群欢迎正常学习elk的朋友扫码交流.
elk

转载请注明: 转自Rainbird的个人博客
   本文链接: ELK|kafka增加及删除topic

Posted in ELK | Tagged , , , , | Leave a comment

ELK|kafka增加分区或调整副本数


kafak管理常用的工具是kafka-manager和kakfa-eagle.这两个工具在分区管理上都是只管加不管减,副本调整的话,也不支持,只能自己手工操作.本文的操作也是去年双十一的沉淀,没想到今年又用了一次,索性记录下来.

修改

这里需要一个json文件,示例如下

bash-4.3# cat increase-replication-factor.json 
{
    "version":1,
    "partitions":[
        {
            "topic":"test-topic",
            "partition":0,
            "replicas":[
                1
            ]
        },
        {
            "topic":"test-topic",
            "partition":1,
            "replicas":[
                2
            ]
        },
        {
            "topic":"test-topic",
            "partition":2,
            "replicas":[
                3
            ]
        }
    ]
}

需要增加分区,就增加下面的块

{
    "topic":"test-topic",
    "partition":4,
    "replicas":[
        3
    ]
}

其中partition要不重复,replicas要根据节点数循环.

需要增加副本,就修改

"replicas":[
    3,2
]

两个副本就有两位,三个副本就有三位.

执行修改
会返回当前的配置,记得保存一下,万一搞错了,恢复时用

bash-4.3# kafka-reassign-partitions.sh \
--zookeeper 192.168.0.1:2181 \
--reassignment-json-file increase-test-topic.json \
--execute
Current partition replica assignment

{"version":1,"partitions":[{"topic":"test-topic","partition":0,"replicas":[3],"log_dirs":["any"]},{"topic":"test-topic","partition":2,"replicas":[2],"log_dirs":["any"]},{"topic":"test-topic","partition":1,"replicas":[1],"log_dirs":["any"]}]}

Save this to use as the --reassignment-json-file option during rollback

验证修改
需要清楚,无论分区的增加还是副本的调整都有一个过程,会有数据的移动,再进行后面的操作前要等上一个操作完成

bash-4.3# kafka-reassign-partitions.sh \
--zookeeper 192.168.0.1:2181 \
--reassignment-json-file increase-test-topic.json \
--verify

Status of partition reassignment: 
Reassignment of partition test-topic-0 completed successfully
Reassignment of partition test-topic-1 completed successfully
Reassignment of partition test-topic-2 completed successfully

错误一则

Partitions reassignment failed due to Partition reassignment data file is empty
kafka.common.AdminCommandFailedException: Partition reassignment data file is empty
        at kafka.admin.ReassignPartitionsCommand$.parseAndValidate(ReassignPartitionsCommand.scala:266)
        at kafka.admin.ReassignPartitionsCommand$.executeAssignment(ReassignPartitionsCommand.scala:194)
        at kafka.admin.ReassignPartitionsCommand$.executeAssignment(ReassignPartitionsCommand.scala:190)
        at kafka.admin.ReassignPartitionsCommand$.main(ReassignPartitionsCommand.scala:61)
        at kafka.admin.ReassignPartitionsCommand.main(ReassignPartitionsCommand.scala)Partitions reassignment failed due to Partition reassignment data file is empty
kafka.common.AdminCommandFailedException: Partition reassignment data file is empty
        at kafka.admin.ReassignPartitionsCommand$.parseAndValidate(ReassignPartitionsCommand.scala:266)
        at kafka.admin.ReassignPartitionsCommand$.executeAssignment(ReassignPartitionsCommand.scala:194)
        at kafka.admin.ReassignPartitionsCommand$.executeAssignment(ReassignPartitionsCommand.scala:190)
        at kafka.admin.ReassignPartitionsCommand$.main(ReassignPartitionsCommand.scala:61)
        at kafka.admin.ReassignPartitionsCommand.main(ReassignPartitionsCommand.scala)

解决:

一般是json文件格式不对,少逗号或多逗号

{
    "version":1,
    "partitions":[
        {"topic":"test_topic","partition":0,"replicas":[1,2,3]},
        {"topic":"test_topic","partition":1,"replicas":[1,2,3]},
        {"topic":"test_topic","partition":2,"replicas":[1,2,3]}
        {"topic":"test_topic","partition":3,"replicas":[1,2,3]}
    ]
}

弄了一个微信群欢迎正常学习elk的朋友扫码交流.
elk

Posted in ELK | Tagged , , , , | Leave a comment

ELK|Kafka命令操作困扰

kafka是一个分布式消息订阅系统,我司一直用它来做日志中转队列,配合ELK,一直表现很出色.当然,基本每次和它打交道的时候都是遇到队列堆积的情况,基本一年一次,去年是双十一,今年也是.之所以要记录一下,是因为同样的错误一年遇到一次,每次都要重新学习一遍,好记性不如赖笔头.

kafka安装

首先说明一下背景,kafka是通过容器运行的.
类似

docker run -dt \
 --restart=always \
 --name=kafka1 \
 -h kafka1 \
 -p 9092:9092 \
 -p 9999:9999 \
 -v /data:/kafka \
 -v /opt/kafka/logs:/opt/kafka/logs \
 -e KAFKA_ZOOKEEPER_CONNECT=xx.xx.xx.xx:2181\
 -e KAFKA_BROKER_ID=1 \
 -e KAFKA_HEAP_OPTS="-Xmx20G -Xms20G" \
 wurstmeister/kafka:1.0.0

问题一

JVM报错误无法分配内存:Cannot allocate memory

bash-4.3# kafka-topics.sh

Java HotSpot(TM) 64-Bit Server VM warning: INFO: os::commit_memory(0x00000002c0000000, 21474836480, 0) failed; error='Cannot allocate memory' (errno=12)
#
# There is insufficient memory for the Java Runtime Environment to continue.
# Native memory allocation (mmap) failed to map 21474836480 bytes for committing reserved memory.
# An error report file with more information is saved as:
# //hs_err_pid3290.log


这个问题的原因是因为设置了环境变量KAFKA_HEAP_OPTS="-Xmx20G -Xms20G".估计每次运行java命令都会按这个配置尝试分配20G内存吧,因为kafka主进程运行已经用去了20G,自然不可能再分配出来这么多了.
解决办法也很简单,直接去掉这个设置就好了

bash-4.3# unset KAFKA_HEAP_OPTS

JMX报错

一波刚平,一波又起.再次运行命令还是报错

bash-4.3# kafka-topics.sh
Error: JMX connector server communication error: service:jmx:rmi://kafka1:9999


JMX是Java Management Extensions,它是一个Java平台的管理和监控接口。用来监控kafka运行情况的.基于前面的经验,这个问题大概率也是环境变量引起的.
解决

unset JMX_PORT

然后就可以愉快的玩耍了

弄了一个微信群欢迎正常学习elk的朋友扫码交流.
elk

转载请注明: 转自Rainbird的个人博客
   本文链接: ELK|Kafka命令操作困扰

Posted in ELK | Tagged , , , , | Leave a comment

Python|把你喜欢的照片合成到微信头像

缘起

轩轩小朋友一直在学习画画,前段时间画了张哪吒的图,看着着实让人喜欢

本来想直接换成微信头像的,又觉得有失个性,还是研究一下,怎么放到头像的右下角吧.

开工

把大象放进冰箱总共分几步呢
第一步:把两张图片都调整成方形
第二步:被合并的图片调整成圆形
第三步:两图合并

环境:
python:3.8.6
Pillow:8.0.1
Pillow就是PIL(Python Imaging Library)了,在Python3叫Pillow,这个之前在<<Python|图片灰化处理>>里提过,是Python处理图片的不二选择.

安装:

 pip install Pillow
  • 把两张图片都调整成方形
    原理就是,取出图片大小,以最小边的为准,从中间缩小

    from PIL import Image
    
    def crop_square(img):
    x, y = img.size
    center = (int(x/2), int(y/2))
    length = int(min(x, y)/2)
    left_top = (center[0] - length, center[1] - length)
    right_buttom = (center[0] + length, center[1] + length)
    new_img = img.crop(left_top + right_buttom)
    return new_img
  • 被合并的图片调整成圆形
    先打开图片,然后调成方形,再调整成圆形并保存

    def img_circle(img_path,cir_path):
    ima = Image.open(img_path).convert("RGBA")
    ima = crop_square(ima)
    size= ima.size
    r2  = size[0]
    r3  = int(r2/2)
    imb = Image.new('RGBA', (r3*2, r3*2))
    pima= ima.load() # 像素的访问对象
    pimb= imb.load()
    r   = float(r2/2) #圆心横坐标
    for i in range(r2):
        for j in range(r2):
            lx = abs(i-r) #到圆心距离的横坐标
            ly = abs(j-r) #到圆心距离的纵坐标
            l = (pow(lx,2) + pow(ly,2))** 0.5 # 三角函数 半径
            if l < r3:
                pimb[i-(r-r3),j-(r-r3)] = pima[i,j]
    imb.save(cir_path)
  • 两图合并
    注释的比较明白了,比较困难的是图片去背景花了一些时间

    def img_join(file_bg,file_front,end_png):
    #打开原始图片,切成方形,并调整大小
    img_bg  = crop_square(Image.open(file_bg)).resize((573,573))
    #打开上层图片并调整大小
    img_front = Image.open(file_front).resize((250,250))
    #上层图片合并到原始图片,并透明上层背景
    r, g, b, a = img_front.split()
    img_bg.paste(img_front, (323,323),mask=a)
    img_bg.save(end_png)

    使用
    准备两张图片,指定输出路径,走你.

    if __name__ == '__main__':
    base_name       = 'nezha'
    file_front      =f'./img/{base_name}.jpg'
    cir_file_name   =f'./img/cir_{base_name}.png'
    img_circle(file_front,cir_file_name)
    end_png         =f'./img/end_{base_name}.jpg'
    img_join(file_bg,cir_file_name,end_png)

    接入到公众号

    以为到这里就结束了吗?
    为了换个微信图像,需要从手机传一张图片到电脑,python合成,再传回手机,再去微信设置,似乎很繁琐,还不容易批量复制:妈妈想要怎么办,爷爷奶奶姥姥姥爷想要怎么办?技术就是生产力,怎样简化这个步骤呢?把这个功能放到微信公众号不就可以了吗,微信公众号发送一张图片,收到图片以后,处理再返回,直接微信保存,再设置头像,完美.

    点击最下面的 +
    选择一张图片上传.
    然后回复相应的数字就可以了.
    得到图片以后再去个人中心设置.
    对了,顺便把姜子牙,大圣,还有疯狂动物城里的兔朱迪和狐尼克也加上了.

Posted in Python | Tagged , , , , , , , , , , | Leave a comment

ELK|ES管理之又见 UNASSIGNED SHARD

在ES集群管理过程中,分区(shard)出现unassigned是遇到了比较多的情况了.原因很多常见的两个:节点意外重启(NODE_LEFT),磁盘空间不足(No space left on device).而我最近遇到的情况:操之过急或者说重启节点姿势不正确,造成主分区挂掉,日志无法写入,以至于拖慢整个index.比较宝贵的实战经验记录一下
本文相关版本信息
elasticsearch:6.0.0
kibana:6.0.0
以下操作在 kibana 自带的DevTools进行

查看集群状态

一般出现分区未分配的时候,整个集群的状态都会变成RED

GET _cluster/health

{
  "cluster_name": "cluster_name",
  "status": "green",
  "timed_out": false,
  "number_of_nodes": 5,
  "number_of_data_nodes": 5,
  "active_primary_shards": 89,
  "active_shards": 109,
  "relocating_shards": 0,
  "initializing_shards": 0,
  "unassigned_shards": 0,
  "delayed_unassigned_shards": 0,
  "number_of_pending_tasks": 0,
  "number_of_in_flight_fetch": 0,
  "task_max_waiting_in_queue_millis": 0,
  "active_shards_percent_as_number": 100
}

当然现在状态是正常的,如果不正常的话"status"不是"green"

  "status": "green",
  "active_shards_percent_as_number": 100

"active_shards_percent_as_number"不会是100,以下三个指标也会各有数字

  "relocating_shards": 0,
  "initializing_shards": 0,
  "unassigned_shards": 0,
  "delayed_unassigned_shards": 0,

应对异常

查询shard异常

GET _cat/shards?v&s=state&h=index,shard,prirep,state,unassigned.reason
index                         shard prirep state   unassigned.reason
zzzlog-2020.11.05             1     p      STARTED 
zzzlog-2020.11.05             2     p      STARTED 
zzzlog-2020.11.05             3     p      STARTED 
syslog-2020.11.05             2     r      STARTED 
syslog-2020.11.05             1     p      STARTED 
syslog-2020.11.05             3     r      STARTED 

上面只是示例一下,有异常的话,unassigned.reason那列会有相应的显示
当然,也可以查询指定的index

GET _cat/shards?v&s=state&h=index,shard,prirep,state,unassigned.reason&index=syslog*
index             shard prirep state   unassigned.reason
syslog-2020.11.05 1     p      STARTED 
syslog-2020.11.05 3     p      STARTED 
syslog-2020.11.05 2     p      STARTED 

查询具体原因

GET /_cluster/allocation/explain?pretty
{
  "error": {
    "root_cause": [
      {
        "type": "remote_transport_exception",
        "reason": "[sys-es-001][xx.xx.xx.xx:9300][cluster:monitor/allocation/explain]"
      }
    ],
    "type": "illegal_argument_exception",
    "reason": "unable to find any unassigned shards to explain [ClusterAllocationExplainRequest[useAnyUnassignedShard=true,includeYesDecisions?=false]"
  },
  "status": 400
}

如果是磁盘不足,或者是节点意外重启,经过上面两步基本就可以看出来了.
节点重启的话,一般起来以后,ES集群是自动再同步一次数据,很快未分配的分区就会消失
磁盘不足自然需要手动扩容或添加磁盘,相应的,重启以后也会有很大的概率自动恢复
当然这里有一个失败次数最大五次的概念,达到次数了,再手动触发一下就好了.

POST /_cluster/reroute?retry_failed=true

对了,有时候直接查询集群分配失败原因/_cluster/allocation/explain并查不到任何东西.我们通过_cat/shards已经知道具体哪个index有问题了,这时候可以直接查询指定的索引

GET /_cluster/allocation/explain?pretty
{
  "index": "syslog-2020.11.04",
  "shard": 2,
  "primary": true
}

一般的感冒发烧,到这里就结束了,如果是重症再继续往下看喽

疑难杂症

同样的症状可能原因有很多,以下几招是我运维ES集群两年的经验结晶了.

分区重建之修改索引副本数

有时候分区unassigned状态始终恢复不了,可以尝试调整一下分区的副本数,或增加或减少,大概率会管用

PUT syslog-2020.11.03/_settings
{
  "settings": {
    "index.number_of_replicas": "1"
  }
}

number_of_replicas只要与当前不一致即可.什么不知道当前副本数?查之

GET syslog-2020.11.03/_settings?filter_path=**.number_of_replicas

{
  "syslog-2020.11.03": {
    "settings": {
      "index": {
        "number_of_replicas": "3"
      }
    }
  }
}

哦,对,上面这个filter_path也是个好东西,数据量大时绝对好用

分区重建之手动修改分区节点

既然在这个节点上一直失败,咱换个节点好了

POST _cluster/reroute
{
  "commands": [
    {
      "move": {
        "index": "syslog-2020.08.04",
        "shard": 2,
        "from_node": "es2-master",
        "to_node": "es3-master"
      }
    }
  ]
}

当然,这一招的正经用法是ES集群磁盘分布不匀,手动将磁盘使用过度的分区调到空闲节点

分区重建之创建空分区

分区失败也有可能,是因为里面的数据乱了,丢弃一部分,换来集群正常也是值得的

POST _cluster/reroute
{
  "commands": [
    {
      "allocate_empty_primary": {
        "index": "syslog-2020.08.17",
        "shard": 7,
        "node": "es5-data",
        "accept_data_loss":true
      }
    }
  ]
}

两害相较取其轻,放弃分区数据相对整个索引数据要好接受不少

分区重建绝招之放弃数据

既然放弃分区的数据不行,那便放弃这个index之前写入的所有数据,毕竟后面还有不少要写入不是

DELETE syslog-2020.08.17

这一招算是釜底抽薪了,需要接受数据丢失带来的风险

分区重建绝招之放弃节点

这招是头两天的意外发现,因为那天确实日志量大采集不进来,但是又出了几个线上问题,急需查日志,当时的念头就是无论如果,不能放弃数据.因为只有一个index的一个分区有问题,其它日志还在正常写,但是日志量又大,很快把这个节点的磁盘写满了,想着反正es一会儿也得自动均衡磁盘,直接手动标记这个节点下线算了.

PUT _cluster/settings
{
  "transient": {
    "cluster.routing.allocation.exclude._ip": "xx.xx.xx.xx"
  }
}

意外的,竟然发现不能创建的那个index的分区自动创建了.谢天谢地!
集群正常了,可以再考虑把这个节点加回来

PUT _cluster/settings
{
  "transient": {
    "cluster.routing.allocation.exclude._ip": null
  }
}

这个问题的表现是state:INITIALIZING,unassigned.reason: ALLOCATION_FAILED,又一个主分区,还是0副本.当时的查询记录还有:

GET /_cluster/allocation/explain?pretty
{
  "index": "syslog-2020.11.04",
  "shard": 2,
  "primary": true
}

{
  "index": "syslog-2020.11.04",
  "shard": 2,
  "primary": true,
  "current_state": "initializing",
  "unassigned_info": {
    "reason": "ALLOCATION_FAILED",
    "at": "2020-11-04T14:34:03.022Z",
    "failed_allocation_attempts": 5,
    "details": "failed recovery, failure RecoveryFailedException[[syslog-2020.11.04][2]: Recovery failed on {es-005}{zVzh5mpxSam4dGTFkgh3FA}{ZzWZcNLGT_SgS6tTdguBtQ}{xx.xx.xx.xx}{xx.xx.xx.xx:9300}{box_type=hot}]; nested: IndexShardRecoveryException[failed to recover from gateway]; nested: EngineException[failed to recover from translog]; nested: AlreadyClosedException[this IndexWriter is closed]; nested: IOException[No space left on device]; ",
    "last_allocation_status": "no"
  },
  "current_node": {
    "id": "zVzh5mpxSam4dGTFkgh3af",
    "name": "es-005",
    "transport_address": "xx.xx.xx.xx:9300",
    "attributes": {
      "box_type": "hot"
    }
  },
  "explanation": "the shard is in the process of initializing on node [es-005], wait until initialization has completed"
}

后话

最后还是想提一下敬畏之心.
大数据,什么是大数据呢.一天几百G,历史数据十几T.虽然是日志系统,这么大的数据量,任何一个小的操作都要谨慎谨慎再谨慎.因为你的一个小失误,都是大量的数据或移动或消失或产生,影响都是很难承受的.像前面说的增加副本数number_of_shards,直接的结果就是主机CPU飙升,磁盘疯狂读写,内网网卡几百兆带宽以支撑这么大量的数据交换
最后一句送给自己:es集群很优秀,几十亿条数据毫秒级查询,如果你感觉es搜索慢,99.99%的原因是因为你自己不优秀,没发挥出来es的价值

弄了一个微信群欢迎正常学习elk的朋友扫码交流.
elk

Posted in ELK | Tagged , , , , , , , , | Leave a comment

云闪付乘北京地铁省三元,真香!

作为北京地铁的忠实用户,一直都在使用官方的亿通行App.支付渠道一直是哪个有优惠用哪个,从最早的京东支付,到后来的支付宝,再到后来的工商,再到这之前一直用支付宝的月卡.
云闪付的这个优惠,当初也看到了,也试了一次,还真1分钱成功支付一次,只是第二次就原价了,还心里暗骂了一句:骗子(现在人都咋回事儿?便宜没占上,还不说人好:)
前几天,突发奇想,又打开了云闪付这个App,翻来翻去又看到了这样活动,才咣然大悟,原来自己使用的姿势不对!!!特别写了这篇文章,分享一下.
优惠时间
2020.09.21~2020.11.30
时间不多了,赶紧上车.
优惠内容
活动一: 新人1分钱乘地铁.简单来说,就是你以前没用过云闪付的乘车码,第一次使用,有机会实现1分钱蹭车.(个人理解是第一次使用乘车码,不是第一次使用云闪付)
活动二: 1折乘地铁.这也是我当前使用的优惠,一次省三块钱(最高优惠)

关键来了
首先要有云闪付App
苹果链接放一个,安卓用户自己想办法喽

其次,使用App里的二维码
使用App里的二维码!!!
使用App里的二维码!!!
使用App里的二维码!!!
重点的事件多说几遍,我上次就卡这了.想使用这个优惠,直接用云闪付App里的乘车码,不需要再打开亿通行了.

鲁迅说过:有便宜赶紧沾.

然后就愉快的开始省钱之旅吧.

Posted in 原创 | Tagged , , , , | Leave a comment

Python|fastapi输出定制(四)

随着fastapi学习的深入,渐渐的不满足返回json这种格式,想要url重定向怎么办?想输出纯文本怎么办?想直接返回一个文件怎么办?这节来回答这些问题
直接查看fastapi.responses的源码,我们看到以下定义好的返回类型

from starlette.responses import FileResponse  # noqa
from starlette.responses import HTMLResponse  # noqa
from starlette.responses import JSONResponse  # noqa
from starlette.responses import PlainTextResponse  # noqa
from starlette.responses import RedirectResponse  # noqa
from starlette.responses import Response  # noqa
from starlette.responses import StreamingResponse  # noqa
from starlette.responses import UJSONResponse  # noqa


下面,开始我们的表演

URL重定向

用nginx来搞的话,一般配置301或者302,不过fastapi返回HTTP重定向,默认状态码为307(临时重定向)。

from fastapi import FastAPI
from fastapi.responses import RedirectResponse

app = FastAPI()

@app.get("/blog")
go_to_blog():
    return RedirectResponse("https://blog.cnrainbird.com")

curl查看

curl -I -XGET http://0.0.0.0:8001/blog
HTTP/1.1 307 Temporary Redirect
date: Sat, 17 Oct 2020 07:52:01 GMT
server: uvicorn
location: https://blog.cnrainbird.com
transfer-encoding: chunked

输出纯文本

这次用到的是PlainTextResponse,直接打印个Hello world吧

from fastapi import FastAPI
from fastapi.responses import PlainTextResponse

app = FastAPI()

@app.get("/", response_class=PlainTextResponse)
def main():
    return "Hello World"

输出文件

这次选手叫:FileResponse异步流式输出一个文件。
不同于其他返回,FileResponse可以传入更多参数:

path       - 文件路径
headers    - 定制头信息,字典格式
media_type - media type,如果没有设置则会根据文件名或文件路径来推断media type
filename   - 文件名。如果设置,会被包含到response的Content-Disposition中

文件response会包含合适的Content-Length, Last-Modified 以及 ETag 头信息内容。

示例

from fastapi import FastAPI
from fastapi.responses import FileResponse

some_file_path = "large-video-file.mp4"
app = FastAPI()

@app.get("/")
def main():
    return FileResponse(some_file_path)

定制默认类

比如,我们不想每次return时都再写类型,想直接全局定义返回文本怎么呢?

from fastapi import FastAPI
from fastapi.responses import PlainTextResponse

app = FastAPI(default_response_class=PlainTextResponse)

@app.get("/")
def main():
    return "Hello World"

结语

还有一些其它的类型,大同小异,不一一演示了.弄了一个微信群欢迎正常学习fastapi的朋友扫码加入.
fastapi

转载请注明: 转自Rainbird的个人博客
   本文链接: Python|fastapi输出定制(四)

Posted in Python | Tagged , , , , , , , , | Leave a comment

修身|2020年十一辟谷(断食)记录

这应该是2020年最后的疯狂了.
前面两篇辟谷总结也说.这个过程最重要的是保暖,五一开始是个合适的时间,十一转冷应该是最后上车的机会
先上图再说收获

时间确切的说是1号到5号中午,体重从开始的141.6降到了134.0,降幅7.6斤.表格是1号做好的,计划八天假期拿出七天来进行这个事儿,但是到5号的时候发现身体素质的得分已经到了95分.假期过半,目标达成,于是想着就此打住,多拿出一些时间来陪家人.
对于这次体重的下调还是很满意的.要知道67公斤,上一次这个体重的时候还是2008的青龙湖龙舟赛的时候,之所以印象深刻是因为那会儿小身板太轻,划龙舟的时候都不太容易找到另一边体重相当的小伙伴.
关于得分.这一项在小米运动中叫身体指数 得分.它是结合身高,体脂,水分,体内肌肉等多维度的数据,进行综合分析后,得出的一个参考性分数.可以帮助了解自身健康状况.
之前称体重的时候也一直有看到这个数据,只是没太当一回事儿,只是有一次得到过90分,然后就再也没有过了.这次顺道把这个统计上了.可以看到,分数一直在朝好的方向发展.
没有对比就没有伤害,这样,拿出五一时的数据,看一下

  • 从体重上看
    五一花了五天时间,减掉7.1斤.十一花了四天半,减掉7.6斤,基本上说可以是完胜.
    五一的结束点是145.1,十一的起点是141.6.半年的时间体重下降3.5斤.说明了一个很关键的问题:半年没有反弹.感谢这半年努力的自己!!!

  • 身体指数
    五一的指数从60到74,十一的指数从78到95.看起来五一减的还是有些匆忙,可以说是时间短任务重.因为时间的关系见好就收了,而十一的情况是时间还好,目标已然达成.

  • 个人感受
    努力,只为遇见最好的自己!
    4号,5号都开始6点自然醒了.除了假期已经休息了几天没有压力外,感觉身体肌能达到了健康状态,尤其6号去爬了趟山,感觉轻轻松松,毫无压力.用我媳妇儿的话:就这架式,看不出来是五天没吃饭的人.

北漂15年,一直低头向前冲,向前冲;想飞得高,想飞得更高;想跑的快,想跑的更快;终于冷不丁的体重恢复到了12年前,不由得让我思考:打拼可以,保重身体.如今有了这个好的契机,接下来会在标准的体重下,重新起飞

立个flag: 2021年1月8号,元旦时,再回顾一次体重.

Posted in 原创 | Tagged , , , , , , , | Leave a comment

Python|fastapi之隐藏docs(安全初探)(三)

fastapi开发api确实fast.东西开发完了,前后端调试也方便,要上线了,怎么保证接口文档不被非法访问呢?简单想了几个场景

内网部署

将swagger的入口监听在内网,域名访问的话,也直接解析成内网,外网不能访问也是个不错的选择.

直接关闭

这招算是釜底抽薪了,直接关门,咱都不访问.算是最简单有效的办法.
代码

app = FastAPI(
    docs_url=None,
    redoc_url=None
)

动态开关

默认关闭,确实有需要查看,临时打开,用完关闭,也是个不错的选择.
原理就是:访问/docs时,默认没有,通过另一个接口临时调整一个参数,这时才允许访问.
主要代码

app = FastAPI(
    docs_url=None,
    redoc_url=None
)
@app.get('/add_docs')
def show_docs_by_manager():
    logger.info(app.docs_url)
    msg = 'ok'
    if app.docs_url is None:
        app.docs_url = '/docs'
        msg = 'docs is open !'
    else:
        app.docs_url = None
        msg = 'docs is disabled !'
    logger.info(app.docs_url)
    return response_struct(msg=msg)
@app.get("/docs")
async def get_documentation():
    if app.docs_url is None:
        return response_struct()
    else:
        return get_swagger_ui_html(openapi_url="/openapi.json", title="docs")

如上,需要访问时,直接/add_docs接口,也不添加参数了,访问一次打开,再访问一次关闭,这样就实现了动态开关的目的.

开启basic auth

出发点就是访问/docs时进行一次用户名和密码认证,用nginx的话很容易实现
示例代码

echo "username:$(openssl passwd -crypt 'password')" >> /home/.htpasswd

location /docs {
    auth_basic  "请输入密码";
    auth_basic_user_file /etc/apache2/.htpasswd; 
}

既然nginx能实现,我牛掰fastapi自然也可以.
代码

from fastapi import Depends, FastAPI, HTTPException
from fastapi.security import HTTPBasic, HTTPBasicCredentials
from starlette.status import HTTP_401_UNAUTHORIZED
from fastapi.openapi.docs import get_swagger_ui_html
app = FastAPI(
    docs_url=None
)

security = HTTPBasic()

@app.get("/docs",include_in_schema=False)
async def get_documentation(credentials: HTTPBasicCredentials = Depends(security)):
    if credentials.username != "rainbird" or credentials.password != "pwd":
        raise HTTPException(
            status_code=HTTP_401_UNAUTHORIZED,
            detail="Incorrect email or password",
            headers={"WWW-Authenticate": "Basic"},
        )
    else:
        return get_swagger_ui_html(openapi_url="/openapi.json", title="docs")


如上,访问/docs需要验证,用户名是rainbird,密码是pwd

结尾

本文只是简单的示范了swagger的页面安全问题.对于后端接口,内部访问的话最好就是直接放内网,也不需要加密和认证,性能会好一些.如果接口一定要放公网的话除了考虑好swagger的安全,还要处理好接口的访问权限,切莫要门户大开,锁都不加.

fastapi

Posted in Nginx, Python | Tagged , , , , , , , | Leave a comment