对python3 requests包的网络请求抓包时,https请求会报错,错误如下:
1 | [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed |
这时需要增加抓包工具用到的自签名证书,步骤如下:
- 终端执行命令
python3 -m certifi
,查看CA证书存放位置 - 将抓包工具生成的自签名证书内容(pem格式)复制到上面提示的文件中
对python3 requests包的网络请求抓包时,https请求会报错,错误如下:
1 | [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed |
这时需要增加抓包工具用到的自签名证书,步骤如下:
python3 -m certifi
,查看CA证书存放位置全文搜索属于最常见的需求,开源的 Elasticsearch 是目前全文搜索引擎的首选。它可以快速地储存、搜索和分析海量数据。维基百科、Stack Overflow、Github 都采用它。
Elasticsearch 的底层是开源库 Lucene。Elasticsearch 是 Lucene 的封装,提供了 REST API 的操作接口,开箱即用。
原理简介参考终于有人把Elasticsearch原理讲透了!
节点 Node、集群 Cluster 和分片 Shards
ElasticSearch 是分布式数据库,允许多台服务器协同工作,每台服务器可以运行多个实例。单个实例称为一个节点(node),一组节点构成一个集群(cluster)。
分片是底层的工作单元,文档保存在分片内,分片又被分配到集群内的各个节点里,每个分片仅保存全部数据的一部分。
索引 Index、类型 Type 和文档 Document
方便理解,对比我们比较熟悉的 MySQL 数据库:
index → db
type → table
document → row
这是一个不恰当的比喻。在数据库中,table之间是相互独立的,两个table中相同名字的column之间无关联。
但在Elasticsearch中,Index下不同Type中Document的同名field是同一个,必须要有相同的映射定义。具体参考官方文档。
所有其他语言可以使用 RESTful API 通过默认端口 9200 和 Elasticsearch 进行通信。一个 Elasticsearch 请求和任何 HTTP 请求一样由若干相同的部件组成:
curl -X<VERB> '<PROTOCOL>://<HOST>:<PORT>/<PATH>?<QUERY_STRING>' -d '<BODY>'
被 < > 标记的部件:
部件名作用
VERB:适当的 HTTP 方法 或 谓词 : GET、 POST、 PUT、 HEAD 或者 DELETE。
PROTOCOL:http 或者 https
HOST:Elasticsearch 集群中任意节点的主机名,或者用 localhost 代表本地机器上的节点。
PORT:运行 Elasticsearch HTTP 服务的端口号,默认是 9200 。
PATH:API 的终端路径(例如 _count 将返回集群中文档数量)。Path 可能包含多个组件,例如:_cluster/stats 和 _nodes/stats/jvm 。
QUERY_STRING:任意可选的查询字符串参数 (例如 ?pretty 将格式化地输出 JSON 返回值,使其更容易阅读)
BODY:一个 JSON 格式的请求体 (如果请求需要的话)
示例
1 | curl -XGET 'http://localhost:9200/_count?pretty' -d ' |
增加:
1 | POST /db/user/1 |
这一段代码稍微解释一下,这其实就往索引为 db 类型为 user 的数据库中插入一条 id 为 1 的一条数据,这条数据其实就相当于一个拥有 username/password/age 三个属性的一个实体,就是 JSON 数据
执行命令后,Elasticsearch 返回如下数据:
1 | # POST /db/user/1 |
version 是版本号的意思,当我们执行操作会自动加 1
删除:
1 | DELETE /db/user/1 |
Elasticsearch 返回数据如下:
1 | { |
这里就可以看到 version 变成了 2
修改:
1 | PUT /db/user/2 |
Elasticsearch 返回数据如下:
1 | { |
查询:
1 | GET /db/user/2 |
返回数据如下:
1 | { |
请求_search接口时,某些客户端不支持GET请求中有Body,需将GET改为POST。
先往 Elasticsearch 中插入一些数据:
1 | PUT /movies/movie/1 |
现在已经把一些电影信息放入了索引,可以通过搜索看看是否可找到它们。 为了使用 ElasticSearch 进行搜索,我们使用 _search 端点,可选择使用索引和类型。
也就是说,按照以下模式向URL发出请求:
换句话说,为了搜索电影,可以对以下任一URL进行POST请求:
http://localhost:9200/_search - 搜索所有索引和所有类型。
http://localhost:9200/movies/_search - 在电影索引中搜索所有类型
http://localhost:9200/movies/movie/_search - 在电影索引中显式搜索电影类型的文档。
如果只是发送一个请求到上面的URL,我们会得到所有的电影信息。为了创建更有用的搜索请求,还需要向请求正文中提供查询。
请求正文是一个JSON对象,除了其它属性以外,它还要包含一个名称为 “query” 的属性,这就可使用ElasticSearch的查询DSL。
1 | { "query": { //Query DSL here } } |
DSL是ElasticSearch自己基于JSON的域特定语言,可以在其中表达查询和过滤器。可以把它简单同SQL对应起来,相当于条件语句。
查询DSL具有一长列不同类型的查询可以使用。 对于“普通”自由文本搜索,最有可能想使用一个名称为“查询字符串查询”。
查询字符串查询是一个高级查询,有很多不同的选项,ElasticSearch将解析和转换为更简单的查询树。如果忽略了所有的可选参数,并且只需要给它一个字符串用于搜索,它可以很容易使用。
现在尝试在两部电影的标题中搜索有“kill”这个词的电影信息:
1 | GET /_search |
在前面的例子中,使用了一个非常简单的查询,一个只有一个属性 “query” 的查询字符串查询。 如前所述,查询字符串查询有一些可以指定设置,如果不使用,它将会使用默认的设置值。
这样的设置称为“fields”,可用于指定要搜索的字段列表。如果不使用“fields”字段,ElasticSearch查询将默认自动生成的名为 “_all” 的特殊字段,来基于所有文档中的各个字段匹配搜索。
为了做到这一点,修改以前的搜索请求正文,以便查询字符串查询有一个 fields 属性用来要搜索的字段数组:
1 | GET /_search |
1 | GET /_search |
1 | GET /_search |
1 | GET /_search |
1 | GET /_search |
1 | GET /_search |
1 | GET /_search |
1 | GET /_search |
1 | GET /_search |
1 | GET /_search |
1 | GET /_search |
term是代表完全匹配,即不进行分词器分析,文档中必须包含整个搜索的词汇。
match和term的区别是,match查询的时候,elasticsearch会根据给定的字段提供合适的分析器,而term查询不会有分析器分析的过程,match查询相当于模糊匹配,只包含其中一部分关键词就行。
1 | GET /_search |
match_phrase 称为短语搜索,要求所有的分词必须同时出现在文档中,同时位置必须紧邻一致。
1 | GET /_search |
聚合分析是数据库中重要的功能特性,完成对一个查询的数据集中数据的聚合计算,如:找出某字段(或计算表达式的结果)的最大值、最小值,计算和、平均值等。ES作为搜索引擎兼数据库,同样提供了强大的聚合分析能力。
对一个数据集求最大、最小、和、平均值等指标的聚合,在ES中称为指标聚合(metric)
而关系型数据库中除了有聚合函数外,还可以对查询出的数据进行分组group by,再在组上进行指标聚合。在 ES 中group by 称为分桶,桶聚合(bucketing)
ES中还提供了矩阵聚合(matrix)、管道聚合(pipleline),但还在完善中。
在查询请求体中以aggregations节点按如下语法定义聚合分析:
1 | { |
aggregations 也可简写为 aggs
聚合计算的值可以取字段的值,也可是脚本计算的结果。
获取指定字段最大值
1 | GET /_search |
获取查询结果指定字段最小值,按指定字段排序
1 | GET /_search |
指定field,在脚本中用_value 取字段的值
1 | { |
注意接口地址为_count
1 | GET /_count |
1 | GET /_search |
1 | GET /_search |
1 | GET /_search |
1 | GET /_search |
1 | GET /_search |
1 | GET /_search |
1 | GET /_search |
1 | GET /_search |
elasticsearch-head将是一款专门针对于elasticsearch的客户端工具,提供Chrome浏览器插件。仓库地址https://github.com/mobz/elasticsearch-head 。
Choose Runtime
CodeGlance
GitToolBox
Grep Console
Key Promoter X
Maven Helper
Rainbow Brackets
RestfulToolkit
String Manipulation
trojan是近两年兴起的网络工具,项目官网https://github.com/trojan-gfw ,文档官网是 https://trojan-gfw.github.io/trojan 。与强调加密和混淆的SS/SSR等工具不同,trojan将通信流量伪装成互联网上最常见的https流量,从而有效防止流量被检测和干扰。
终端输入如下命令:
1 | sudo bash -c "$(curl -fsSL https://raw.githubusercontent.com/trojan-gfw/trojan-quickstart/master/trojan-quickstart.sh)" |
该命令会下载最新版的trojan并安装。安装完毕后,trojan配置文件路径是 /usr/local/etc/trojan/config.json
重点关注以下属性:
local_port
:监听的端口,默认是443,下文中因为要将Trojan放在Nginx后,因此改为了别的端口;remote_addr
和remote_port
:非trojan协议时,将请求转发处理的地址和端口。可以是任意有效的ip/域名和端口号,默认是本机和80端口。一般是伪装的web站点服务;password
:密码。需要几个密码就填几行,最后一行结尾不能有逗号;cert
和key
:域名的证书和密钥;key_password
:默认没有密码(如果证书文件有密码就要填上)根据自己的需求修改配置文件,保存,然后设置开机启动:systemctl enable trojan
,并启动trojan: systemctl start trojan
。
Trojan 默认端口为443,接管了所有443端口的流量,其他请求则是通过Trojan转发到了其他服务,例如nginx。如果有需求是将Trojan放在nginx后面,由nginx统一接收流量再分发到Trojan和其他服务(web,v2ray),可以参考下面的配置。
要实现上面的需求,用到了nginx的stream_ssl_preread_module模块,具体资料可以参考 http://nginx.org/en/docs/stream/ngx_stream_ssl_preread_module.html 。
编译nginx时增加此模块。
1.将Trojan配置文件的local_port
改为非443
端口,例如9443
。将nginx原有443
端口的配置改为非443
端口,例如8443
。
2.nginx.conf
中添加如下配置
1 | stream { |
执行nginx -t
测试配置文件,若提示nginx: [emerg] unknown directive "stream" in XXX
,则在nginx.conf
中的events
区块前增加下面的语句
1 | load_module /usr/lib/nginx/modules/ngx_stream_module.so; |
具体原因参考 https://serverfault.com/questions/858067/unknown-directive-stream-in-etc-nginx-nginx-conf86 。
以上就是Trojan放在Nginx后面的配置流程。
1 | #!/usr/bin/env bash |
db.system.profile.find({"op" : "query","ns" : "poetries", millis : { $gt : 100 },ts : { $gt : new ISODate("2018-06-07T00:00:00.000Z"),$lt : new ISODate("2018-06-07T10:00:00.000Z")}}).pretty()
db.getProfilingLevel() 1为开启
为了方便填写git commit message,写了一个脚本用于读取jira上的issues,并列出选择作为commit message。 用到了git hook中的prepare-commit-msg 下面提供bash shell和python3两个版本 1.bash shell 此版本需要安装jq。
#!/bin/bash
USERNAME=`git config --get user.name`
if [ "$2" = "message" -o "$2" = "commit" ]
then
exit 0
fi
exec 2> /dev/null
ISSUS=`curl -u jira:jira "http://localhost:8081/rest/api/2/search?jql=status+in+(Reopened,%20%22To%20Do%22,%20%22In%20Progress%22)%20AND%20assignee%20in%20($USERNAME)%20ORDER%20BY%20updated%20DESC" | jq '.issues[]|{summary: .fields.summary, key: .key}'`
KEYS=(`echo $ISSUS | jq '.key'`)
SUMMARYS_TMP=("`echo $ISSUS | jq '.summary'`")
IFS_old=$IFS
IFS=$'\n'
SUMMARYS=($SUMMARYS_TMP)
IFS='"'
number=${#KEYS[@]}
declare -a ISSUSES='()'
for((i=0;i<$number;i++))
do
ISSUSES[$i]="${KEYS[$i]}${SUMMARYS[$i]}"
done
for((j=0;j<${#ISSUSES[@]};j++))
do
let k=$j+1
echo $k.${ISSUSES[$j]}
done
exec < /dev/tty
exec 2>&1
read -p "请输入编号:"
let answer=$REPLY-1
echo ${ISSUSES[$answer]} > $1
IFS=$IFS_old
2.python3
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys, os, re
from subprocess import check_output
import requests
import json
def query_report(user):
s = requests.Session()
s.post('http://localhost:8081/rest/auth/1/session', json={"username":"jira","password":"jira"})
url = 'http://localhost:8081/rest/api/2/search?jql=status+in+(Reopened,%20%22To%20Do%22,%20%22In%20Progress%22)%20AND%20assignee%20in%20(' + user +')%20ORDER%20BY%20updated%20DESC'
reports = s.get(url)
return reports.json()
sys.stdin = open('/dev/tty')
# 收集参数
commit_msg_filepath = sys.argv[1]
if len(sys.argv) > 2:
commit_type = sys.argv[2]
else:
commit_type = ''
if len(sys.argv) > 3:
commit_hash = sys.argv[3]
else:
commit_hash = ''
if commit_type == "message":
sys.exit(0)
# 检测我们所在的分支
branch = check_output(['git', 'symbolic-ref', '--short', 'HEAD']).strip()
branch = str(branch, 'utf-8')
print("On branch '%s'" % branch)
username = check_output(['git', 'config', '--get', 'user.name']).strip()
username = str(username, 'utf-8')
messages = []
if branch.startswith('master'):
j = query_report(username)
if j["total"] > 0:
issues = j["issues"]
for i in range(len(issues)):
print(str(i+1) + ':' + issues[i]["key"] + " " + issues[i]["fields"]["summary"])
messages.append(issues[i]["key"] + " " + issues[i]["fields"]["summary"]);
number = input("请输入编号: ")
message = messages[int(number) - 1]
with open(commit_msg_filepath, 'w') as f:
f.seek(0, 0)
f.write(message)
sudo apt-get install openjdk-7-jdk git-core gnupg flex bison gperf build-essential \
zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 \
lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z-dev ccache \
libgl1-mesa-dev libxml2-utils xsltproc unzip
#新建目录
mkdir workspace
cd workspace
#链接为清华镜像,--repo-url是repo工具的地址,--no-repo-verify关闭repo工具验证
repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest -b android-6.0.1_r79 --repo-url=https://mirrors.tuna.tsinghua.edu.cn/git/git-repo --no-repo-verify
#-d用清单文件里的版本;-c当前分支;--no-tags不拉取tag
repo sync -d -c --no-tags
#初始化环境
source build/envsetup.sh
#选择产品
lunch
#用16线程编译
make -j16
有一个不在.gitmodule文件中的submodule在更新,解决办法就是
git ls-files --stage | grep 160000
这可以看到所有的Submodule文件,然后
git rm --cached PATH
Android开发中,不可避免的可能会引用到外部so文件,设置一个项目中可能需要引用多个不同的外部so文件。因为不同的引入库中so文件的目录可能不同,导致打包后生成的项目lib目录中的目录结构是不同的外部so文件目录的合集。可能会出现armeabi/armeabi-v7a/arm64-v8a/x86/mips等,一般情况下,armeabi应该是有的,当此三个目录下的文件可能不同时,在某些特定机型下很可能会出现UnsatisfiedLinkError。
原因在于不同的机型CPU结构不同导致搜寻不同的目录下面的包,而由于外部库不同的so文件目录可能armeabi下还有a、b so文件,而x86下可能只含有a。例如一个应用armeabi下有liba.so
、libb.so
,arm64-v8a下有liba.so
这样的应用装在arm64的设备上,当代码掉到加载libb.so时就会有上面的异常出现,即便是armeabi下有此so,系统也不会去寻找,原因是这个apk中已经有arm64的目录了。
此时解决方案如下:
在build.gradle中添加如下内容
android {
defaultConfig {
ndk {
abiFilters 'armeabi'
}
}
}
这样生成的apk中就只包含armeabi下的so文件,而不包含其他架构的目录,这样系统会采取兼容模式,加载armeabi下的so文件。