豪翔天下

Change My World by Program

0%

基本框架

项目常用项目结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from flask import Flask, request
app = Flask(__name__)

@app.route('/', methods=['GET', 'POST']) # 定义仅接收哪些类型的请求
def hello():
if request.method == 'POST':
return "POST"
return "Hello World!"

# 带参数的路由
@app.route('/<username>')
def func(username)
@app.route('/post/<int:post_id>')

if __name__ == "__main__":
app.run(debug=True, host='0.0.0.0', port='5000')

但是,业界普遍认为,tornadoflask同时使用能够同时发挥两个框架的有点,前者用于异步处理高并发请求,后者便于编写,这时候torando作为一个httpserver对外提供http访问,flasktornado更加简单易用,只是因为flask在生产环境是需要WSGI server的,所以Tornado是非常适合的,至少比Apache作为server好,而前面的nginx也只是作为负载。Flask's build-in server is not suitable for production as it doesn't scale well and by default serves only one request at a time——Deployment Options

请求和响应

request

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 获取表单提交数据, 仅用于表单
request.form.get('begin', '')

# 获取POST数据
request.json
request.json.get('username')

# 获取GET参数
request.args.get('q', '')

# 处理get请求
data = request.get_json(silent=False)
request.query_string # 获取字符串形式的query string

# 获取header头
request.headers.get('Auth-Token')

# 获取用户真实IP
if request.headers.getlist('X-Forwarded-For'):
ip = request.headers.getlist('X-Forwarded-For')[0]
else:
ip = request.remote_addr

# 获取并保存上传的文件
obj = request.files.get('field1')
print(obj.filename)
obj.save('/path/filename.jpg')

resposne

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 返回指定状态码
return make_response(jsonify({'a': 'b'}), 201)
return jsonify({'a': 'b'}), 201 # 也可以简单点这样做

# 返回JSON数据
from flask import jsonify
return jsonify(username=g.user.username, email='asd')
return jsonify({'username': g.user.username})

# 允许CORS,可以使用flask-cors库,也可以全局设置如下这个
@app.after_request
def after_request(response):
response.headers.add('Access-Control-Allow-Origin', '*')
response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization')
response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS')
return response

## 如果仅针对单独的接口,可以添加装饰器,当然,该接口必须允许OPTIONS请求,才能直接返回请求
def allow_cross_domain(fun):
@wraps(fun)
def wrapper_fun(*args, **kwargs):
rst = make_response(fun(*args, **kwargs))
rst.headers['Access-Control-Allow-Origin'] = '*'
rst.headers['Access-Control-Allow-Methods'] = 'PUT,GET,POST,DELETE,PATCH'
allow_headers = "Referer,Accept,Origin,User-Agent"
rst.headers['Access-Control-Allow-Headers'] = allow_headers
return rst
return wrapper_fun

中间件

1
2
3
4
5
6
7
8
9
10
11
12
13
@app.before_request
def before(request):
pass

@app.after_request
def after(response):
return response

# 全局错误处理
@app.errorhandler(Exception)
def handle_exception(e: Exception):
traceback.print_exc()
return jsonify({'error': str(e)}), 500

数据库

使用flask-sqlalchemy操作数据库,具体文档可以参考SQLAlchemy手册flask-sqlalchemy帮我们做了很多我们其实不用关心的操作,例如自动新建和关闭session,但是需要注意的是,flask-sqlalchemy默认会在每次使用session的时候开启一个事务,每次请求完成自动结束事务,所以千万不要用它来运行长任务,否则事务一直不关闭,会导致表级锁,无法对表进行操作

常用扩展

flask-jwt-extended

  • jwt扩展
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
token = create_access_token(identity={'id': 1, 'role': 'admin'})

@app.route(...)
@jwt_required() # 必须在路由上加上这个装饰器
def test():
user = get_jwt_identity() # 直接获取identity的数据

# 顺便可以写个验证中间件
def admin_only(func):
@wraps(func)
def wrapper(*args, **kwargs):
user = get_jwt_identity()
if user.get('role') != 'admin':
return jsonify({'error': 'Admin only operation'}), 401
return func(*args, **kwargs)
return wrapper

flask-bcrypt

  • bcrypt扩展,加密密码用

flask-socketio

  • 需要注意的是必须安装eventlet依赖才能使用websocket协议,否则是通过http协议来实现的,还是会没几秒发送轮训请求
1
socketio = SocketIO(app, cors_allowed_origins='*')	# 允许跨域cors

TroubleShooting

  • AssertionError: View function mapping is overwriting an existing endpoint function: main: 原因可能是在给控制器函数添加装饰器的时候没有重新定义其名称,导致每个使用该装饰器的控制器的签名都一样了,可以这样设置控制器:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    def route_decorator(func):
    def wrapper():
    try:
    return func()
    except Exception as e:
    print(str(e))
    return {"message": str(e), "success": False, "code": 500}
    wrapper.__name__ = func.__name__ # 需要将签名设置为和以前的函数签名一致
    return wrapper

安装方法

支持python3mysql drivermysqlclientpymysql,不推荐只支持2的MySQLdb

1
2
3
4
5
6
7
8
9
10
11
# ubuntu
sudo apt-get install python3-dev gcc libmysqlclient-dev
pip install mysqlclient

# CentOS
sudo yum install pytho36-devel mysql-devel # python36-devel指定python版本
sudo yum install mariadb-devel MariaDB-shared # 如果不安装会出现cannot find -lmariadb错误
pip install mysqlclient

# Mac m1/Apple Silicon
export ARCHFLAGS="-arch x86_64"
阅读全文 »

官网说: “高度包容、快速而极简的Node.js Web框架”,我认为Express最大的优点是可用于API开发,而不是web开发,首先,它的路由定义简单,其次,nodejs天生的异步特性使得其性能极佳。

安装与启动

1
2
3
4
5
6
npm install express-generator -g   # 安装应用程序生成器
express myapp # 生成一个名为myapp的工程目录
cd myapp && npm install # 安装依赖项
DEBUG=myapp:* npm start # MacOS或Linux上启动

DEBUG=express:* node app.js # 打开调试模式

然后在浏览器访问http://localhost:3000/即可访问应用程序了。

最简单的例子(这个例子基本不能处理任何其他的请求,除非用上面的生成器来生成,就会带了一些解析请求生成响应的功能):

1
2
3
4
5
6
7
8
9
10
11
12
13
var express = require('express');
var app = express();

// 如果不加下面这个,那么req.body是undefined的
app.use(express.json());

app.get('/', function (req, res) {
res.send('Hello World!');
});

app.listen(3000, function () {
console.log('Example app listening on port 3000!');
});

请求与响应

请求

1
2
3
4
5
6
7
8
9
10
// 获取请求参数,比如访问的事http://192.168.1.1:6004/code?code=xxxxx
req.query.name // 获取get参数
req.params.id // 获取路由中用冒号定义的参数
req.body.name // 获取POST参数

req.url // 例如:/?code=xxxxx
req.originalUrl // 例如:/code?code=xxxxx
req.baseUrl // /code
req.path // 为什么是/,这里的path应该是指除去路由部分,比如app.use('/code')除去这部分
req.get('host') // 192.168.1.1:6004

响应

1
2
3
res.redirect(301, 'http://google.com')	// 301响应
res.status(200).json({}) // JSON响应
res.send('<html></html>') // 直接响应HTML内容

路由

路由结构定义为:app.METHOD(PATH, HANDLER),例如

1
2
3
4
5
app.get('/', function(req, res){
res.send('Hello World!');
})

app.post('/*', function(req, res){}); // 使用通配符的路由参数

中间件

中间件函数能够访问请求对象(req)、相应对象(res)以及应用程序的请求/相应循环中的下一个中间件函数。

app.use([path], function)用于加载处理http请求的中间件(middleware),请求会以此被use的顺序处理。

服务器

  1. 安装服务(pypi)已经没怎么维护了,这里直接从github拉取源码

    1
    2
    3
    yum install git -y
    git clone -b master https://github.com/shadowsocks/shadowsocks.git
    cd shadowsocks && python3.6 setup.py install

    安装完成后使用ssserver -p 443 -k password -m aes-256-gcm(完整daemon命令ssserver -p 443 -k password -m aes-256-gcm --log-file /var/log/ssserver -d start)进行测试(不再推荐其他协议),从客户端发起连接,发现能科学上网了。

  2. 设置开机启动

    mkdir /etc/shadowsocks

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    vim /etc/shadowsocks/config.json
    # 在config.json中复制入以下配置:
    {
    "server":"0.0.0.0",
    "server_port":8388,
    "local_address": "127.0.0.1",
    "local_port":1080,
    "password":"yourpassword",
    "timeout":300,
    "method":"aes-256-gcm"
    }

    其中端口和密码可按需进行修改

  3. 启动服务``ssserver -c /etc/shadowsocks/config.json`

新机器一键安装脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
yum update && yum groupinstall -y 'development tools'
yum install -y zlib-dev openssl-devel sqlite-devel bzip2-devel xz-libs git wget

wget https://www.python.org/ftp/python/3.6.0/Python-3.6.0.tar.xz
xz -d Python-3.6.0.tar.xz
tar -xvf Python-3.6.0.tar
cd Python-3.6.0
./configure && make && sudo make altinstall
cd

git clone https://github.com/shadowsocks/shadowsocks.git
cd shadowsocks && git checkout -b master origin/master
python3.6 setup.py install

ssserver -p 443 -k zuguowansui -m aes-256-gcm --log-file /var/log/ssserver -d start

客户端

  1. 安装必要的软件

    1
    2
    3
    4
    yum install -y epel-release
    yum install -y python
    yum install python-pip privoxy # privoxy用于将ss转换为http代理,代理端口默认为8118
    pip install shadowsocks
  2. 修改相应的配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #vim /etc/shadowsocks.json
    {
    "server": "250.250.250.250",
    "server_port": "2333",
    "local_address": "0.0.0.0",
    "local_port": 1086,
    "password": "",
    "method": "rc4-md5"
    }
  3. 启动服务

    1
    2
    nohup sslocal -c /etc/shadowsocks.json /dev/null 2>&1 &	# 后台执行
    echo " nohup sslocal -c /etc/shadowsocks.json /dev/null 2>&1 &" >> /etc/rc.local # 开机自动启动

Socks5代理转换为HTTP代理

  • 需要注意的是,export的时候应该是小写http_proxy,大写在某些系统里面不起作用

使用的软件叫做privoxy

1
2
3
4
5
sudo apt-get install privoxy
# sudo vim /etc/privoxy/config,将ss代理的配置设置进去,另外可以在该配置文件里面修改日志级别,可以打印更详细的日志
forward-socks5 / 127.0.0.1:1086 .
# 然后重启,sudo /etc/init.d/privoxy restart即可
export http_proxy=127.0.0.1:8118 # 默认代理端口是8118

TroubleShooting

pytest

Python的测试类,调研了一下nose和pytest,虽然nose的使用量确实比pytest多一点,但是活跃度并不高,从15年后就没发布新版本了,而pytest的github还在一直刷。所以选择了pytest来学习python的测试。

常用命令

1
2
3
pytest test.py		# 测试脚本
pytest -x # 当第一次出现失败的时候就停止测试
pytest --maxfail=2 # 设置最大失败次数

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class TestName:	# 测试类必须以Test开头
def setup_class(self):
"""测试类开始的时候执行,相当于__init__"""
def teardown_class(self):
"""测试类结束的时候执行,相当于__del__"""
def setup_method(self):
"""每个测试方法开始的时候执行"""
def teardown_method(self):
"""每个测试方法结束的时候执行"""
def test_one(self): # 测试方法必须以test_开头
assert 1 is 2

with pytest.raises(MyException) as e: # 断言下面的语句会抛出指定的错误
x = 1/1

mock对象

mock确实是用来代替我们的测试对象。表面上看,用了mock那还干嘛要测试,其实,不明白的原因是mock的应用场景并不是单纯地代替测试对象,而是代替的那些在当前测试用例并不十分必要,而且该测试对象耗时或者不稳定,和我们真正要测试的代码逻辑无关,那么久可以使用mock来模拟该对象的返回值,实现我们真正想要的测试用例。比如我们现在是要测试函数b,但是函数b却依赖函数a,我们在这里并不关心a,只需要拿到它的返回值而已,所以可以用mock来模拟,以防止a函数本身可能发生的不稳定、耗时等现象。
另外,mock还可以用来保存几个测试用例的全局变量(要说的话,几个测试用例之间是不能有依赖的,只是我现在的场景是需要登录一个网站然后测试里面的功能,只能用mock来保存cookies)pytest测试类是不能更改类变量的。比如:

1
2
3
4
5
6
7
8
9
class TestClass:
var1 = '123'
mock = mock.Mock()

def testLogin(self):
r = requests.post(url, data={})
self.mock.cookies.return_value = r.cookies.items()
def testFun(self):
r = request.get(url, cookies=self.mock.cookies())
扩展阅读

supervisor是使用Python编写的进程管理软件,在实际开发中,一般用它来同时开始一批相关的进程,无论是Django的runserver还是直接管理Nginx、Apache等,都比较方便,这里是其使用方法:

安装supervisor

1
2
3
4
5
6
7
# ubuntu
apt-get install supervisor
service supervisor restart

# centos
yum install supervisor
/etc/init.d/supervisord restart
阅读全文 »

Tornado

中文文档
是不是很神奇,我居然会学习除Django以外的另一种Python Web框架。但事实确实如此,我学了,并且用了一下,感觉和Django确实存在很大的不同的。
学这个的主要原因是要参加饿了么的黑客马拉松,主题是使用Python或Java或Node设计Resutful API,来应对高并发的请求,保证数据的一致性。虽然最后的分数并不理想,但是在这次比赛中学到了很多的东西,Tornado就是其中之一。
以前只听说过Tornado比Django拥有更高的并发和异步特性,只听过Django坚持自己造轮子,其他语言的Web框架也只用过PHP的Laravel,当安装完Tornado后完全不知道该怎么玩儿,怎么着玩意儿自己不会生成一个项目,项目的框架还要自己写。后来才体会到,这样的好处,简洁、直观、轻便,它只提供最基础的东西,其他一切问题都由你自己来解决,同时,短短几千行的源代码,在遇到问题的时候,我们完全可以直接看源代码来查找问题出在哪儿,这就是简洁带来的好处。另外异步的作用也只有在实际需要的时候才能体会出来。由于我从来没写过异步的代码,所以,只是按照之前写代码那样,而没有根据异步的特性来实现,异步的代码是要在会阻塞的地方使用回调函数来实现,所以,我的程序并不能得高分。不过后来才知道Tornado通过gen将同步代码转换为异步的实现。

要想自己定义代码结构,可以参考qiwsir/TornadoWheel

阅读全文 »

原文链接:http://ju.outofmemory.cn/entry/108566

fuck,最讨厌java了,有同事说JKS是Java特有的东西,所以必须调用Java才能使用,but,I use Python,nothing is im
possible,发现使用requests来直接调用其它格式的证书文件就行,当然,Python也可以用pyjks包来将jks转换为其它格式,但没必要那样做,
因为直接用ssl工具转换就可以一劳永逸了。

JKS(Java
KeyStore)是Java的一个证书仓库,包括授权整数和公钥整数等。JDK提供了一个工具keytool用于管理keystore。转换步骤:

  1. 使用keytool导出成PKCS12格式:

    keytool -importkeystore -srckeystore server.jks -destkeystore server.p12 -srcstoretype jks -deststoretype pkcs12

    输入目标密钥库口令:

再次输入新口令:
输入源密钥库口令:  

已成功导入别名 ca_root 的条目。
已完成导入命令: 1 个条目成功导入, 0 个条目失败或取消
  1. 生成pem证书(包含了key,server证书和ca证书):

    生成key 加密的pem证书

    $ openssl pkcs12 -in server.p12 -out server.pem
    Enter Import Password:
    MAC verified OK
    Enter PEM pass phrase:
    Verifying - Enter PEM pass phrase:

# 生成key 非加密的pem证书




$ openssl pkcs12 -nodes -in server.p12 -out server.pem
Enter Import Password:
MAC verified OK
  1. 单独导出key:

    生成加密的key

    $ openssl pkcs12 -in tankywoo.p12 -nocerts -out server.key
    Enter Import Password:
    MAC verified OK
    Enter PEM pass phrase:
    Verifying - Enter PEM pass phrase:

# 生成非加密的key




$ openssl pkcs12 -in tankywoo.p12 -nocerts -nodes -out server.key
Enter Import Password:
MAC verified OK
  1. 单独导出server证书:

    $ openssl pkcs12 -in server.p12 -nokeys -clcerts -out server.crt
    Enter Import Password:
    MAC verified OK

  2. 单独导出ca证书:

    $ openssl pkcs12 -in server.p12 -nokeys -cacerts -out ca.crt
    Enter Import Password:
    MAC verified OK

TroubleShooting:

1.至于原文中出现的导入ca_root证书出现错误,它那个方法貌似不管用,这里建议将Java升级到Java8即可成功导入。

2.在Python中使用ssl时(无论是用httplib、ssl还是requests),可能出现以下错误:

Traceback (most recent call last):
  File "client.py", line 10, in <module>
    ssl_sock.connect(('', 9000))
  File "/Users/amk/source/p/python/Lib/ssl.py", line 204, in connect
    self.ca_certs)
ssl.SSLError: [Errno 0] _ssl.c:327: error:00000000:lib(0):func(0):reason(0)

根本原因就是提供的证书是错误的

原文地址:http://coolshell.cn/articles/10822.html

本篇文章写于2013年底,而今天我看来,依然是精华中的精华,就喜欢这种深入浅出的文章,带我们对函数式编程更深入的理解,并且本篇文章采用多种语言多种角度来
向我们讲解了到底什么才是函数式编程,再加上最近工作上很多的问题,才发现,其实公司之前的代码有很多优秀的地方。

原文地址:http://coolshell.cn/articles/10822.html

本篇文章写于2013年底,而今天我看来,依然是精华中的精华,就喜欢这种深入浅出的文章,带我们对函数式编程更深入的理解,并且本篇文章采用多种语言多种角度来
向我们讲解了到底什么才是函数式编程,再加上最近工作上很多的问题,才发现,其实公司之前的代码有很多优秀的地方。

当我们说起函数式编程来说,我们会看到如下函数式编程的长相:

  • 函数式编程的三大特性:

  • *immutable data 不可变数据**:像Clojure一样,默认上变量是不可变的,如果你要改变变量,你需要把变量copy出去修改。这样一来,可以让你的程序少很多Bug。因为,程序中的状态不好维护,在并发的时候更不好维护。(你可以试想一下如果你的程序有个复杂的状态,当以后别人改你代码的时候,是很容易出bug的,在并行中这样的问题就更多了)

  • *first class functions**:这个技术可以让你的函数就像变量一样来使用。也就是说,你的函数可以像变量一样被创建,修改,并当成变量一样传递,返回或是在函数中嵌套函数。这个有点像Javascript的Prototype(参看Javascript的面向对象编程

  • *尾递归优化**:我们知道递归的害处,那就是如果递归很深的话,stack受不了,并会导致性能大幅度下降。所以,我们使用尾递归优化技术——每次递归时都会重用stack,这样一来能够提升性能,当然,这需要语言或编译器的支持。Python就不支持。

    • 函数式编程的几个技术
  • map & reduce* :这个技术不用多说了,函数式编程最常见的技术就是对一个集合做Map和Reduce操作。这比起过程式的语言来说,在代码上要更容易阅读。(传统过程式的语言需要使用for/while循环,然后在各种变量中把数据倒过来倒过去的)这个很像C++中的STL中的foreach,find_if,count_if之流的函数的玩法。

  • *pipeline**:这个技术的意思是,把函数实例成一个一个的action,然后,把一组action放到一个数组或是列表中,然后把数据传给这个action list,数据就像一个pipeline一样顺序地被各个函数所操作,最终得到我们想要的结果。

  • recursing 递归* :递归最大的好处就简化代码,他可以把一个复杂的问题用很简单的代码描述出来。注意:递归的精髓是描述问题,而这正是函数式编程的精髓。

  • *currying**:把一个函数的多个参数分解成多个函数, 然后把函数多层封装起来,每层函数都返回一个函数去接收下一个参数这样,可以简化函数的多个参数。在C++中,这个很像STL中的bind_1st或是bind2nd。

  • *higher order function 高阶函数**:所谓高阶函数就是函数当参数,把传入的函数做一个封装,然后返回这个封装函数。现象上就是函数传进传出,就像面向对象对象满天飞一样。

    • 还有函数式的一些好处
  • *parallelization 并行:所谓并行的意思就是在并行环境下,各个线程之间不需要同步或互斥。lazy evaluation 惰性求值:这个需要编译器的支持。表达式不在它被绑定到变量之后就立即求值,而是在该值被取用的时候求值,也就是说,语句如x:=expression; (把一个表达式的结果赋值给一个变量)明显的调用这个表达式被计算并把结果放置到 x 中,但是先不管实际在 x 中的是什么,直到通过后面的表达式中到 x 的引用而有了对它的值的需求的时候,而后面表达式自身的求值也可以被延迟,最终为了生成让外界看到的某个符号而计算这个快速增长的依赖树。determinism 确定性**:所谓确定性的意思就是像数学那样 f(x) = y ,这个函数无论在什么场景下,都会得到同样的结果,这个我们称之为函数的确定性。而不是像程序中的很多函数那样,同一个参数,却会在不同的场景下计算出不同的结果。所谓不同的场景的意思就是我们的函数会根据一些运行中的状态信息的不同而发生变化。

上面的那些东西太抽象了,还是让我们来循序渐近地看一些例子吧。

我们先用一个最简单的例子来说明一下什么是函数式编程。

先看一个非函数式的例子:

1

2

3

4

|

int cnt;

void increment(){

cnt++;

}

—|—

那么,函数式的应该怎么写呢?

1

2

3

|

int increment(int cnt){

return cnt+1;

}

—|—

你可能会觉得这个例子太普通了。是的,这个例子就是函数式编程的准则:不依赖于外部的数据,而且也不改变外部数据的值,而是返回一个新的值给你

我们再来看一个简单例子:

1

2

3

4

5

6

7

8

9

10

|

def inc(x):

def incx(y):

return x+y

return incx

inc2 = inc(2)

inc5 = inc(5)

print inc2(5) # 输出 7

print inc5(5) # 输出 10

—|—

我们可以看到上面那个例子inc()函数返回了另一个函数incx(),于是我们可以用inc()函数来构造各种版本的inc函数,比如:inc2()和inc5()
。这个技术其实就是上面所说的Currying技术。从这个技术上,你可能体会到函数式编程的理念:把函数当成变量来用,关注于描述问题而不是怎么实现,这样
可以让代码更易读。

Map & Reduce

在函数式编程中,我们不应该用循环迭代的方式,我们应该用更为高级的方法,如下所示的Python代码

1

2

3

|

name_len = map(len, [“hao”, “chen”, “coolshell”])

print name_len

输出 [3, 4, 9]

—|—

你可以看到这样的代码很易读,因为,这样的代码是在描述要干什么,而不是怎么干

我们再来看一个Python代码的例子:

1

2

3

4

5

6

|

def toUpper(item):

return item.upper()

upper_name = map(toUpper, [“hao”, “chen”, “coolshell”])

print upper_name

输出 [‘HAO’, ‘CHEN’, ‘COOLSHELL’]

—|—

顺便说一下,上面的例子个是不是和我们的STL的transform有些像?

1

2

3

4

5

6

7

8

9

10

11

12

|

#include

#include

#include

using namespace std;

int main() {

string s=”hello”;

string out;

transform(s.begin(), s.end(), back_inserter(out), ::toupper);

cout << out << endl;

// 输出:HELLO

}

—|—

在上面Python的那个例子中我们可以看到,我们写义了一个函数toUpper,这个函数没有改变传进来的值,只是把传进来的值做个简单的操作,然后返回。然后,我
们把其用在map函数中,就可以很清楚地描述出我们想要干什么。而不会去理解一个在循环中的怎么实现的代码,最终在读了很多循环的逻辑后才发现原来是这个或那个意思。
下面,我们看看描述实现方法的过程式编程是怎么玩的(看上去是不是不如函数式的清晰?):

1

2

3

4

|

upname =[‘HAO’, ‘CHEN’, ‘COOLSHELL’]

lowname =[]

for i in range(len(upname)):

lowname.append( upname[i].lower() )

—|—

对于map我们别忘了lambda表达式:你可以简单地理解为这是一个inline的匿名函数。下面的lambda表达式相当于:def func(x):
return x*x

1

2

3

|

squares = map(lambda x: x * x, range(9))

print squares

输出 [0, 1, 4, 9, 16, 25, 36, 49, 64]

—|—

我们再来看看reduce怎么玩?(下面的lambda表达式中有两个参数,也就是说每次从列表中取两个值,计算结果后把这个值再放回去,下面的表达式相当于:(((
(1+2)+3)+4)+5) )

1

2

|

print reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])

输出 15

—|—

Python中的除了map和reduce外,还有一些别的如filter, find, all,
any的函数做辅助(其它函数式的语言也有),可以让你的代码更简洁,更易读。 我们再来看一个比较复杂的例子:

计算数组中正数的平均值

1

2

3

4

5

6

7

8

9

10

11

12

13

|

num =[2, -5, 9, 7, -2, 5, 3, 1, 0, -3, 8]

positive_num_cnt = 0

positive_num_sum = 0

for i in range(len(num)):

if num[i] > 0:

positive_num_cnt += 1

positive_num_sum += num[i]

if positive_num_cnt > 0:

average = positive_num_sum / positive_num_cnt

print average

输出 5

—|—

如果用函数式编程,这个例子可以写成这样:

1

2

|

positive_num = filter(lambda x: x>0, num)

average = reduce(lambda x,y: x+y, positive_num) / len( positive_num )

—|—

C++11玩的法:

1

2

3

4

5

6

7

8

9

10

11

12

|

#include

#include

#include

#include

#include

using namespace std;

vector num {2, -5, 9, 7, -2, 5, 3, 1, 0, -3, 8};

vector p_num;

copy_if(num.begin(), num.end(<span class=”crayon-sy” sty

原文地址:<https://www.digitalocean.com/community/tutorials/apache-vs-nginx-
practical-considerations>

总之就是各有各的优点,最好的方式就是nginx在前面做反向代理,并顺便处理静态内容,而apache则负责处理动态内容。

Introduction

Apache and Nginx are the two most common open source web servers in the world.
Together, they are responsible for serving over 50% of traffic on the
internet. Both solutions are capable of handling diverse workloads and working
with other software to provide a complete web stack.

While Apache and Nginx share many qualities, they should not be thought of as
entirely interchangeable. Each excels in its own way and it is important to
understand the situations where you may need to reevaluate your web server of
choice. This article will be devoted to a discussion of how each server stacks
up in various areas.

General Overview

Before we dive into the differences between Apache and Nginx, let’s take a
quick look at the background of these two projects and their general
characteristics.

Apache

The Apache HTTP Server was created by Robert McCool in 1995 and has been
developed under the direction of the Apache Software Foundation since 1999.
Since the HTTP web server is the foundation’s original project and is by far
their most popular piece of software, it is often referred to simply as
“Apache”.

The Apache web server has been the most popular server on the internet since
1996. Because of this popularity, Apache benefits from great documentation and
integrated support from other software projects.

Apache is often chosen by administrators for its flexibility, power, and
widespread support. It is extensible through a dynamically loadable module
system and can process a large number of interpreted languages without
connecting out to separate software.

Nginx

In 2002, Igor Sysoev began work on Nginx as an answer to the C10K problem,
which was a challenge for web servers to begin handling ten thousand
concurrent connections as a requirement for the modern web. The initial public
release was made in 2004, meeting this goal by relying on an asynchronous(异步),
events-driven(事件驱动) architecture.

Nginx has grown in popularity since its release due to its light-weight
resource utilization and its ability to scale easily on minimal hardware.
Nginx excels at serving static content(静态内容) quickly and is designed to pass
dynamic requests off to other software that is better suited for those
purposes.

Nginx is often selected by administrators for its resource efficiency and
responsiveness under load. Advocates welcome Nginx’s focus on core web server
and proxy features.

Connection Handling Architecturel(连接处理架构)

One big difference between Apache and Nginx is the actual way that they handle
connections and traffic. This provides perhaps the most significant difference
in the way that they respond to different traffic conditions.

Apache

Apache provides a variety of multi-processing modules (Apache calls these
MPMs) that dictate(决定) how client requests are handled. Basically, this allows
administrators to swap out its connection handling architecture easily. These
are:

  • mpm_prefork: This processing module spawns(产生) processes with a single thread each to handle request(一个请求一个线程). Each child can handle a single connection at a time. As long as the number of requests is fewer than the number of processes, this MPM is very fast(请求数量比进程数量少的时候会很快). However, performance degrades quickly after the requests surpass the number of processes, so this is not a good choice in many scenarios. Each process has a significant impact on RAM consumption, so this MPM is difficult to scale effectively. This may still be a good choice though if used in conjunction with other components that are not built with threads in mind. For instance, PHP is not thread-safe, so this MPM is recommended as the only safe way of working with mod_php, the Apache module for processing these files.
  • mpm_worker: This module spawns processes that can each manage multiple threads(每个进程可以管理多个线程). Each of these threads can handle a single connection. Threads are much more efficient than processes(线程比进程更高效), which means that this MPM scales better than the prefork MPM. Since there are more threads than processes, this also means that new connections can immediately take a free thread instead of having to wait for a free process(处理新的连接只需要有新的线程而不需要等待进程释放).
  • mpm_event: This module is similar to the worker module in most situations, but is optimized to handle keep-alive connections(对持久连接进行了优化). When using the worker MPM, a connection will hold a thread regardless of whether a request is actively being made for as long as the connection is kept alive. The event MPM handles keep alive connections by setting aside dedicated(专用的) threads for handling keep alive connections and passing active requests off to other threads. This keeps the module from getting bogged down by keep-alive requests, allowing for faster execution. This was marked stable with the release of Apache 2.4. As you can see, Apache provides a flexible architecture for choosing different connection and request handling algorithms. The choices provided are mainly a function of the server’s evolution and the increasing need for concurrency as the internet landscape has changed.

Nginx

Nginx came onto the scene after Apache, with more awareness of the concurrency
problems that would face sites at scale(更注重并发问题). Leveraging(利用) this
knowledge, Nginx was designed from the ground up to use an asynchronous, non-
blocking, event-driven connection handling algorithm.

Nginx spawns worker processes, each of which can handle thousands of
connections(产生的是worker进程,每个都可以处理上千个连接). The worker processes accomplish this
by implementing a fast looping mechanism(快速的循环机制) that continuously checks for
and processes events. Decoupling(解耦) actual work from connections allows each
worker to concern itself with a connection only when a new event has been
triggered.

Each of the connections handled by the worker are placed within the event loop
where they exist with other connections. Within the loop, events are processed
asynchronously, allowing work to be handled in a non-blocking manner. When the
connection closes, it is removed from the loop.

This style of connection processing allows Nginx to scale incredibly far with
limited resources. Since the server is single-threaded and processes are not
spawned to handle each new connection, the memory and CPU usage tends to stay
relatively consistent, even at times of heavy load.

Static vs Dynamic Content

In terms of real world use-cases, one of the most common comparisons between
Apache and Nginx is the way in which each server handles requests for static
and dynamic content.

Apache

Apache servers can handle static content using its conventional file-based
methods. The performance of these operations is mainly a function of the MPM
methods described above.

Apache can also process dynamic content by embedding(嵌入) a processor of the
language in question into each of its worker instances. This allows it to
execute dynamic content within the web server itself without having to rely on
external components. These dynamic processors can be enabled through the use
of dynamically loadable modules.

Apache’s ability to handle dynamic content internally means that configuration
of dynamic processing tends to be simpler. Communication does not need to be
coordinated with an additional piece of software and modules can easily be
swapped out if the content requirements change.

Nginx

Nginx does not have any ability to process dynamic content
natively(本身无法处理动态内容). To handle PHP and other requests for dynamic content,
Nginx must pass to an external processor for execution and wait for the
rendered content to be sent back(必须使用外部的执行程序然后等待返回). The results can then be
relayed to the client.

For administrators, this means that communication must be configured between
Nginx and the processor over one of the protocols Nginx knows how to speak
(http, FastCGI, SCGI, uWSGI, memcache). This can complicate things slightly,
especially when trying to anticipate the number of connections to allow, as an
additional connection will be used for each call to the processor.

However, this method has some advantages as well. Since the dynamic
interpreter is not embedded in the worker process, its overhead will only be
present for dynamic content. Static content can be served in a straight-
forward manner and the interpreter will only be contacted when needed. Apache
can also function in this manner, but doing so removes the benefits in the
previous section.

Distributed vs Centralized Configuration

For administrators, one of the most readily apparent differences between these
two pieces of software is whether directory-level configuration is permitted
within the content directories.

Apache

Apache includes an option to allow additional configuration on a per-directory
basis by inspecting and interpreting directives in hidden files within the
content directories themselves. These files are known as .htaccess
files.(可以管理每个目录)

Since these files reside within the content directories themselves, when
handling a request, Apache checks each component of the path to the requested
file for an .htaccess file and applies the directives found within. This
effectively allows decentralized configuration of the web server, which is
often used for implementing URL rewrites, access restrictions, authorization
and authentication, even caching policies.

While the above examples can all be configured in the main Apache
configuration file,.htaccess files have some important advantages. First,
since these are interpreted each time they are found along a request path,
they are implemented immediately without reloading the server. Second, it
makes it possible to allow non-privileged users to control certain aspects of
their own web content without giving them control over the entire
configuration file.

This provides an easy way for certain web software, like content management
systems, to configure their environment without providing access to the
central configuration file. This is also used by shared hosting providers to
retain control of the main configuration while giving clients control over
their specific directories.

Nginx

Nginx does not interpret .htaccess files, nor does it provide any mechanism
for evaluating per-directory configuration outside of the main configuration
file. This may be less flexible than the Apache model, but it does have its
own advantages.

The most notable improvement over the .htaccess system of directory-level
configuration is increased performance. For a typical Apache setup that may
allow .htaccess in any directory, the server will check for these files in
each of the parent directories leading up to the requested file, for each
request. If one or more .htaccess files are found during this search, they
must be read and interpreted. By not allowing directory overrides, Nginx can
serve requests faster by doing a single directory lookup and file read for
each request (assuming that the file is found in the conventional directory
structure).

Another advantage is security related(安全). Distributing directory-level
configuration access also distributes the responsibility of security to
individual users, who may not be trusted to handle this task well. Ensuring
that the administrator maintains control over the entire web server can
prevent some security missteps that may occur when access is given to other
parties.

Keep in mind that it is possible to turn off .htaccess interpretation in
Apache if these concerns resonate with you.

File vs URI-Based Interpretation

How the web server interprets requests and maps them to actual resources on
the system is another area where these two servers differ.

Apache

Apache provides the ability to interpret a request as a physical resource on
the filesystem or as a URI location that may need a more abstract evaluation.
In general, for the former Apache uses or blocks, while it
utilizes blocks for more abstract resources.

Because Apache was designed from the ground up as a web server, the default is
usually to interpret requests as filesystem resources. It begins by taking the
document root and appending the portion of the request following the host and
port number to try to find an actual file. Basically, the filesystem hierarchy
is represented on the web as the available document tree.

Apache provides a number of alternatives for when the request does not match
the underlying filesystem. For instance, an Alias directive can be used to map
to an alternative location. Using blocks is a method of working
with the URI itself instead of the filesystem. There are also regular
expression variants which can be used to apply configuration more flexibly
throughout the filesystem.

While Apache has the ability to operate on both the underlying filesystem and
the webspace, it leans heavily towards filesystem methods. This can be seen in
some of the design decisions, including the use of .htaccess files for per-
directory configuration. The Apache docs themselves warn against using URI-
based blocks to restrict access when the request mirrors the underlying
filesystem.

Nginx

Nginx was created to be both a web server and a proxy server. Due to the
architecture required for these two roles, it works primarily with URIs,
translating to the filesystem when necessary.

This can be seen in some of the ways that Nginx configuration files are
constructed and interpreted.Nginx does not provide a mechanism for specifying
configuration for a filesystem directory and instead parses the URI itself.

For instance, the primary configuration blocks for Nginx are server and
location blocks. The server block interprets the host being requested, while
the location blocks are responsible for matching portions of the URI that
comes after the host and port. At this point, the request is being interpreted
as a URI, not as a location on the filesystem.

For static files, all requests eventually have to be mapped to a location on
the filesystem. First, Nginx selects the server and location blocks that will
handle the request and then combines the document root with the URI, adapting
anything necessary according to the configuration specified.

This may seem similar, but parsing requests primarily as URIs instead of
filesystem locations allows Nginx to more easily function in both web, mail,
and proxy server roles. Nginx is configured simply by laying out how to
respond to different request patterns. Nginx does not check the filesystem
until it is ready to serve the request, which explains why it does not
implement a form of .htaccess files.

Modules

Both Nginx and Apache are extensible through module systems, but the way that
they work differ significantly.

Apache

Apache’s module system allows you to dynamically load or unload modules to
satisfy your needs during the course of running the server. The Apache core is
always present, while modules can be turned on or off, adding or removing
additional functionality and hooking into the main server.

Apache uses this functionality for a large variety tasks. Due to the maturity
of the platform, there is an extensive library of modules available. These can
be used to alter some of the core functionality of the server, such as
mod_php, which embeds a PHP interpreter into each running worker.

Modules are not limited to processing dynamic content, however. Among other
functions, they can be used for rewriting URLs, authenticating clients,
hardening the server, logging, caching, compression, proxying, rate limiting,
and encrypting. Dynamic modules can extend the core functionality considerably
without much additional work.

Nginx

Nginx also implements a module system, but it is quite different from the
Apache system. In Nginx, modules are not dynamically loadable, so they must be
selected and compiled into the core software(模块居然不是动态加载的).

For many users, this will make Nginx much less flexible. This is especially
true for users who are not comfortable maintaining their own compiled software
outside of their distribution’s conventional packaging system. While
distributions’ packages tend to include the most commonly used modules, if you
require a non-standard module, you will have to build the server from source
yourself.

Nginx modules are still very useful though, and they allow you to dictate what
you want out of your server by only including the functionality you intend to
use. Some users also may consider this more secure, as arbitrary components
cannot be hooked into the server. However, if your server is ever put in a
position where this is possible, it is likely compromised already.

Nginx modules allow many of the same capabilities as Apache modules. For
instance, Nginx modules can provide proxying support, compression, rate
limiting, logging, rewriting, geolocation, authentication, encryption,
streaming, and mail functionality.

Support, Compatibility, Ecosystem, and Documentation

A major point to consider is what the actual process of getting up and running
will be given the landscape of available help and support among other
software.

Apache

Because Apache has been popular for so long, support for the server is fairly
ubiquitous. There is a large library of first- and third-party documentation
available for the core server and for task-based scenarios involving hooking
Apache up with other software.

Along with documentation, many tools and web projects include tools to
bootstrap themselves within an Apache environment. This may be included in the
projects themselves, or in the packages maintained by your distribution’s
packaging team.

Apache, in general, will have more support from third-party projects simply
because of its market share and the length of time it has been available.
Administrators are also somewhat more likely to have experience working with
Apache not only due to its prevalence, but also because many people start off
in shared-hosting scenarios which almost exclusively rely on Apache due to the
.htaccess distributed management capabilities.

Nginx

Nginx is experiencing increased support as more users adopt it for its
performance profile, but it still has some catching up to do in some key
areas.

In the past, it was difficult to find comprehensive English-language
documentation regarding Nginx due to the fact that most of the early
development and documentation were in Russian. As interest in the project
grew, the documentation has been filled out and there are now plenty of
administration resources on the Nginx site and through third parties.

In regards to third-party applications, support and documentation is becoming
more readily available, and package maintainers are beginning, in some cases,
to give choices between auto-configuring for Apache and Nginx. Even without
support, configuring Nginx to work with alternative software is usually
straight-forward so long as the project itself documents its requirements
(permissions, headers, etc).

Using Apache and Nginx Together

After going over the benefits and limitations of both Apache and Nginx, you
may have a better idea of which server is more suited to your needs. However,
many users find that it is possible to leverage each server’s strengths by
using them together.

The conventional configuration for this partnership is to place Nginx in front
of Apache as a reverse proxy(Nginx做反向代理). This will allow Nginx to handle all
requests from clients. This takes advantage of Nginx’s fast processing speed
and ability to handle large numbers of connections concurrently.

For static content, which Nginx excels at, the files will be served quickly
and directly to the client. For dynamic content, for instance PHP files, Nginx
will proxy the request to Apache, which can then process the results and
return the rendered page. Nginx can then pass the content back to the client.

This setup works well for many people because it allows Nginx to function as a
sorting machine. It will handle all requests it can and pass on the ones that
it has no native ability to serve. By cutting down on the requests the Apache
server is asked to handle, we can alleviate some of the blocking that occurs
when an Apache process or thread is occupied.

This configuration also allows you to scale out by adding additional backend
servers as necessary. Nginx can be configured to pass to a pool of servers
easily, increasing this configuration’s resilience to failure and performance.

Conclusion

As you can see, both Apache and Nginx are powerful, flexible, and capable.
Deciding which server is best for you is largely a function of evaluating your
specific requirements and testing with the patterns that you expect to see.

There are differences between these projects that have a very real impact on
the raw performance, capabilities, and the implementation time necessary to
get each solution up and running. However, these usually are the result of a
series of trade offs that should not be casually dismissed. In the end, there
is no one-size-fits-all web server, so use the solution that best aligns with
your objectives.