ccxt 的代理机制是在发送 HTTP 请求前将端点 API 的地址附加到代理地址之后。在同步模式下,可以直接使用 IP 地址或者基于 HTTP 协议的域名。

exchange = ccxt.okex({
    'verbose': True,
    'proxy': 'http://<proxy>.com/'
})
Request: GET http://<proxy>.com/https://www.okex.com/v2/markets/products.do {
    'User-Agent': 'python-requests/2.18.4', 'Origin': '*', 'Accept-Encoding': 'gzip, deflate'
}

但是 ccxt 目前(v1.13.136)并不支持在异步模式下使用 HTTP 协议的代理,见「#2826」。一种方法是使用 CORS 即服务(CORS-as-a-service)的解决方案,如 https://cors-anywhere.herokuapp.com/https://crossorigin.me/ 等,但它们通常都会有流量限制。关于 CORS(Cross-Origin Resource Sharing,跨源资源共享)的机制,可以参考「Understanding CORS」一文。另一种方法就是在自己的服务器上部署一个支持 HTTPS 的 CORS Anywhere 应用,其作用是在代理的请求中加入 CORS 头部。

服务器环境:香港 VPS;CentOS 7.4;Nginx v1.14.0;node v8.11.1。

配置 Nginx

  • 由于最终需要使用 HTTPS 协议,因此如果是源码编译安装 Nginx 的话,需启用 http_ssl 模块:
./configure --with-http_stub_status_module --with-http_ssl_module
  • 绑定域名(如 cors.<domain>.com),并使用 Nginx 的反向代理。换言之,所有对该域名的请求都会传递到 Node.js 应用中。这里的端口号 8080 和 Node.js 应用绑定的端口号保持一致即可。
# /usr/local/nginx/conf/nginx.conf
http {
    server {
        server_name  cors.<domain>.com;
        location / {
            proxy_pass https://127.0.0.1:8080;
        }
        ...
  • 使用 Certbot 为域名部署免费的 Let's Encrypt SSL 证书(部署前需确保域名已正确解析)。这里分别选择 Nginx 服务器和 CentOS/RHEL7 系统,并且转发所有 HTTP 请求到 HTTPS 上。

注意:手动编译时 Nginx 时,默认会安装到 /usr/local/nginx/sbin/nginx 中。但它通常并不出现在 PATH 环境变量中,因此可以通过软连接的方式确保 Certbot 能检测到系统的 Nginx 模块。

ln -s /usr/local/nginx/sbin/nginx /usr/bin/nginx
ln -s /usr/local/nginx/conf/ /etc/nginx
sudo certbot --nginx
sudo /usr/local/nginx/sbin/nginx -s reload
  • Certbot 会自动将证书配置信息以及 301 跳转规则写入 nginx.conf 中。
# /usr/local/nginx/conf/nginx.conf
http {
    server {
        server_name  cors.<domain>.com;
        listen 443 ssl; # managed by Certbot
        ssl_certificate /etc/letsencrypt/live/cors.<domain>.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/cors.<domain>.com/privkey.pem;
        ...
    }
    server {
        if ($host = cors.<domain>.com) {
            return 301 https://$host$request_uri;
        }
        listen       80;
        server_name  cors.<domain>.com
        return 404;
    }
    ...

配置 CORS Anywhere 应用

  • 部署 CORS Anywhere 应用,可以直接基于上述配置成功的 Nginx 反向代理。直接运行 server.js,代码会读取环境变量指定的主机地址、端口号、黑名单和白名单等,或直接代码中的默认值,如8080端口等。

此时,对 https://cors.<domain>.com 的请求都会被转发到 0.0.0.0:8080 上。

npm install
export PORT=8080
node server.js
> Running CORS Anywhere on 0.0.0.0:8080
curl https://cors.<domain>.com
> This API enables cross-origin requests to anywhere.
> ...
  • 另一种方式是部署独立的 CORS Anywhere 应用,但需要对原生的 server.js 做出一些修改来支持 HTTPS 协议。简单来说,就是读取证书文件(需确保当前用户 user 对证书文件具有读写权限),作为 httpsOptions 选项的参数,并传递给 https.createServer() 方法。

注意:此时是通过 https://cors.<domain>.com:8080 的形式来访问该应用的,因此需要在服务器上开启绑定的端口号。

chmod -R 0770 /etc/letsencrypt/live/
chown -R root:user /etc/letsencrypt/live/
// server-standalone.js
var fs = require('fs');
// ...
var cors_proxy = require('./lib/cors-anywhere');
cors_proxy.createServer({
  httpsOptions: {
    key: fs.readFileSync('/etc/letsencrypt/live/cors.<domain>.com/privkey.pem'),
    cert: fs.readFileSync('/etc/letsencrypt/live/cors.<domain>.com/fullchain.pem')
  },
  // ...
}).listen(port, host, function() {
  console.log('Running CORS Anywhere on ' + host + ':' + port);
});

测试 ccxt 的异步模式

import asyncio
import ccxt.async as ccxt

exchange = ccxt.binance({
    'enableRateLimit': True,
    'proxy': 'https://cors.<domain>.com/'
})

async def poll():
    while True:
        yield await exchange.fetch_tickers()

async def fetch_tickers():
    await exchange.load_markets()
    async for tickers in poll():
        for symbol, ticker in tickers.items():
            print(symbol, ticker['last'])

asyncio.get_event_loop().run_until_complete(fetch_tickers())

已有 2 条评论


  1. David

    请教下,如果修改原生的,根据你的这个和官网提供的,但是就是有问题,求帮忙看下~~~

    David  2018-12-10 18:25回复
  2. David

    这个主要的地方就是https的设置,其他的地方按照博主的是可以的,我在youtube上做了详细的视频说明。

    David  2018-12-26 16:10回复

发表新评论

沪ICP备17018959号-3