MoreRSS

site icondmesg | 小土豆修改

全栈工程师,曾就职于Cisco。
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

dmesg | 小土豆的 RSS 预览

使用Python 通过K线计算技术指标,并用 LLM 预测趋势

2024-12-12 14:22:30

经常混币圈、股票和外汇的朋友们都知道有一个东西叫 K线,大概长这样 使用Python 通过K线计算技术指标,并用 LLM 预测趋势

同时你也可以选择添加更多的图表,如布林线、MACD、RSI等,用这些技术指标来辅助决策。

使用Python 通过K线计算技术指标,并用 LLM 预测趋势

这些技术参数很有用,如果能把一段时间的结果交给LLM去分析,应该比凭着感觉瞎买更靠谱吧!

那这些技术参数是怎么来的呢……?

去花钱买!这个世界上还有什么是钞能力无法解决的事情吗?

使用Python 通过K线计算技术指标,并用 LLM 预测趋势

https://taapi.io/ 已经有人做好了!有股票 也有加密货币的数据。就是……免费版频率限制有些严重,想要获取多点数据就等几个小时吧。一下子升级个 Pro 要花14.99欧元,在PoC阶段好像也不太值得……

实际上,这些技术参数,全部都是使用K线数据,由客户端计算出来的。K线数据很容易获取,很多交易所都提供API,但是计算这些参数需要比较强的数学知识😅

还好已经有人写好了相关的库,虽然是 C/C++写的,但是不怕啦早就有人写好了 Python的wrapper

TA-Lib - Technical Analysis Library

我们需要这个东西来计算数据,这个库支持200多个技术指标,包括RSI,MACD

安装方式可以参考官方文档

获取K线数据

以币安的合约数据为例,非常简单

pip install binance-futures-connector
from binance.um_futures import UMFutures
um_client = UMFutures()
candles=um_client.klines(symbol=‘BTCUSDT’, interval=‘1m’)

这样我们就获取到了 1分钟时间间隔的数据

转换成 pandas的DataFrame 方便后续处理

pd.DataFrame(candles)

计算布林线

布林线使用收盘价格进行计算,而且需要多组数据才可以计算出来

upperband, middleband, lowerband = talib.BBANDS(self.df["close"], timeperiod=20, nbdevup=2, nbdevdn=2, matype=0)

计算 RSI

同样也是收盘价

rsi6 = talib.RSI(self.df["close"], timeperiod=6)
rsi12 = talib.RSI(self.df["close"], timeperiod=12)
rsi24 = talib.RSI(self.df["close"], timeperiod=24)

MACD

收盘价

dif, dea, macd = talib.MACD(self.df["close"], fastperiod=12, slowperiod=26, signalperiod=9)

MA

包括SMA和EMA

sma7 = talib.SMA(self.df["close"], timeperiod=7)
sma25 = talib.SMA(self.df["close"], timeperiod=25)
sma99 = talib.SMA(self.df["close"], timeperiod=99)

ema7 = talib.EMA(self.df["close"], timeperiod=7)
ema25 = talib.EMA(self.df["close"], timeperiod=25)
ema99 = talib.EMA(self.df["close"], timeperiod=99)

转换数据为json

LLM更适合处理json数据,pandas就很方便啦

self.df.to_json(orient="records", date_format="epoch", date_unit="s")

调用 LLM 接口

有了数据之后就可以把他们导出成 json,然后调用LLM进行处理。

这里需要找一个可用的LLM,比如 Mistral AI、OpenAI 、Gemini或者 Claude。由于国内注册比较麻烦,而且风控很严格,建议大家使用「头顶冒火」的API接口

使用什么模型因人而异,一次数据量比较大,gpt-4o可能是比较好的选择,Claude Opus和o1-preview比较贵,但是也可以考虑,头顶冒火网站也都有的

然后要做的事情就是写提示词,让AI分析结果了!🧐

很麻烦是不是……不要怕,我已经写好并且开源了。使用方式详见下一页!⬇️⬇️⬇️ 部分RSS阅读器可能无法显示下一页的内容,请点击链接打开网站阅读


文章版权归原作者所有丨本站默认采用CC-BY-NC-SA 4.0协议进行授权|
转载必须包含本声明,并以超链接形式注明原作者和本文原始地址:
https://dmesg.app/candlestick-llm.html

把 Cloudflare WARP 转换为 http 代理

2024-11-03 20:53:15

Cloduflare WARP真的非常好用,并且支持代理模式。启用这个模式之后,它会在本机监听一个socks端口,应用程序可以配置到这个端口来使用代理。

对于服务器来说,一般使用 warp-cli

warp-cli proxy port 60606
warp-cli mode proxy

之后你就可以 curl

https_proxy=socks5://127.0.0.1:60606 http_proxy=socks5://127.0.0.1:60606 curl ipv4.win
IP: 104.28.157.116 CLOUDFLARE.COM CLOUDFLARE.COM

然而,Go的程序不支持 socks 代理,要手动加transport我可没那个功夫去加。

好消息是,Go默认是尊重环境变量http_proxy的。那么就要想办法给socks代理转换为http代理

这事很简单嘛!用pproxy就好了,别的不会,这个肯定很会!

pproxy -v -l http://127.0.0.1:8118 -r socks5://127.0.0.1:60606

https_proxy=http://127.0.0.1:8118 http_proxy=http://127.0.0.1:8118 curl ipv4.win
curl: (52) Empty reply from server

# pproxy logs
Serving on ipv? 127.0.0.1:8118 by http
http 127.0.0.1:45012 -> socks5 127.0.0.1:60606 -> ipv4.win:80
Unknown remote protocol from 127.0.0.1

把 Cloudflare WARP 转换为 http 代理

怎么报错了呢🤨

可能是 pproxy的问题,那么用gost

gost -L http://127.0.0.1:8118 -F socks5://127.0.0.1:60606
2024/11/03 12:32:43 route.go:700: http://127.0.0.1:8118 on 127.0.0.1:8118
2024/11/03 12:32:46 http.go:162: [http] 127.0.0.1:33284 -> http://127.0.0.1:8118 -> ipv4.win:80
2024/11/03 12:32:46 http.go:257: [route] 127.0.0.1:33284 -> http://127.0.0.1:8118 -> 1@socks5://127.0.0.1:60606 -> ipv4.win:80
2024/11/03 12:32:46 http.go:280: [http] 127.0.0.1:33284 -> 127.0.0.1:8118 : unexpected EOF

把 Cloudflare WARP 转换为 http 代理

那……Privoxy

forward-socks5 / 127.0.0.1:60606 .

也不行!

甚至直接在 Firefox里设置socks5代理,也不行🤨

把 Cloudflare WARP 转换为 http 代理

任何网站都打不开

把 Cloudflare WARP 转换为 http 代理

偶然取消 DNS请求的勾选,就成功了……突然恍然大悟,WARP可能不支持远程解析DNS

 

那么要么用回 socks4

pproxy -v -l http://127.0.0.1:8118 -r socks4://127.0.0.1:60606
gost -L http://127.0.0.1:8118 -F socks4://127.0.0.1:60606

要么给加上DNS的支持

gost -L "http://127.0.0.1:8118?dns=1.1.1.1" -F socks5://127.0.0.1:60606

人生中宝贵的几个小时就这么没了。


文章版权归原作者所有丨本站默认采用CC-BY-NC-SA 4.0协议进行授权|
转载必须包含本声明,并以超链接形式注明原作者和本文原始地址:
https://dmesg.app/warp-http-proxy.html

用 Azure Container Apps 运行PHP网站

2024-10-12 15:10:27

既然是容器,那么也可以跑数据库的吧?那只要再加上一个PHP,就可以跑 WordPress、Typecho之类的应用了!

在 Azure上,用 Container Apps也是可以做到serverless PHP应用的,具体来说就是:

一个pod里开两个容器(不太推荐这种方式),一个是php-apache,一个是MySQL,通过挂载 Azure Files作为volumes来做数据存储。

为什么想这么玩,是因为:

  1. 优化大陆访问,Azure的亚洲机房对大陆访客很友好,因此不能用 Cloudflare
  2. 不想自己管理SSL证书,因此不能用vm
  3. managed database太贵了用不起
  4. FrontDoor也太贵了,每个月要$35的保护费🥹

使用这种方案的好处是,在访问量不是很大的情况下,成本应该可以忽略不计,甚至可以在无访问时缩放到0副本,真正“无服务器” 😂

创建资源组

创建资源组,创建一个vnet,因为存储不想公开给所有人,也方便以后和其他虚拟机内网互通。

创建容器应用

创建的时候,Container Apps Environment 选择已有的虚拟网络

用 Azure Container Apps 运行PHP网站

配置镜像,这个镜像是我自己构建的,基于 php:8.3-apache,支持MySQL、PostgreSQL、SQLite,添加了 mod_rewrite,足够给WordPress和Typecho用

用 Azure Container Apps 运行PHP网站

创建存储

Primary Service选择 Azure Files

用 Azure Container Apps 运行PHP网站

创建 File Shares

用 Azure Container Apps 运行PHP网站

我创建了两个,一个是数据库的,一个是网站文件的

用 Azure Container Apps 运行PHP网站

连接 volume到容器

在创建完存储后,去复制一下access key

用 Azure Container Apps 运行PHP网站

在容器环境中添加 SMB

用 Azure Container Apps 运行PHP网站

依次输入信息,这里没有补全,不要输入错了哦

用 Azure Container Apps 运行PHP网站

在容器环境中创建完之后,就可以到容器应用中添加啦

用 Azure Container Apps 运行PHP网站

这里需要注意,数据库的卷可能需要如下额外挂载参数

uid=999,gid=999,nobrl,mfsymlinks,cache=none

容器应用volume

编辑容器,添加volume就可以了

用 Azure Container Apps 运行PHP网站

然后添加一个数据库的sidecar

用 Azure Container Apps 运行PHP网站

如果需要配置环境变量,也可以一起配置了

用 Azure Container Apps 运行PHP网站

最终结果是这样的两个容器,在一个pod里,我这种穷人自然只能选择最低配置啦

用 Azure Container Apps 运行PHP网站

存储安全

默认存储是可以公网访问的(需要用户名密码),为了更安全,我们可以配置为只有某几个虚拟网络可以访问

用 Azure Container Apps 运行PHP网站

配置应用

可能需要进入 console,执行一下创建数据库之类的操作,这点就自行发挥了。

最终结果

在不使用的时候,容器可以缩为0(可以配置为最低1副本)

用 Azure Container Apps 运行PHP网站

在有请求的时候,真的能访问耶,而且还可以自动扩容!

用 Azure Container Apps 运行PHP网站

总结

正常的应用不应该这样配置的,两个容器在同一个pod内耦合也是不理想的。

如果想要利用 Azure的优良线路,正常来说应该选择如下方法之一

  1. Azure VM,自己配置SSL证书,域名解析到这个IP,最经典的操作
  2. Azure FrontDoor + 任意VM,SSL证书可以由FrontDoor管理
  3. Azure应用网关 + 任意VM,解析域名到网关的IP,配置SSL证书,然后上传证书给应用网关
  4. Azure Load Balancer + 任意VM,证书需要在VM上配置好,因为LB是4层的
  5. Container Apps运行PHP,用托管数据库,Container Apps支持托管SSL
  6. Container Apps运行PHP,通过VM运行数据库,两者网络之间创建对等连接
  7. Static Web Apps,只能给静态站点用
  8. Web App + Database,完全托管,价格很感人
  9. Azure Kubernetes Service ,这个我可能不太懂,但是应该可行……

最后……

PHP用什么跑不好要用这个,真是只有真正的赛博精神病才能够想出来这种操作🤡


文章版权归原作者所有丨本站默认采用CC-BY-NC-SA 4.0协议进行授权|
转载必须包含本声明,并以超链接形式注明原作者和本文原始地址:
https://dmesg.app/aca-php.html

Azure Container Apps 连接到虚拟机并配置CPU自动缩放

2024-10-06 15:24:51

我的所有的代码最终都做成了 Docker image,因此可以非常方便的拿出来部署,自然也可以部署在各种 managed container或者managed k8s的环境。

更重要的是,Azure Container Apps 提供一定的免费额度,一般普通用户都够用的了!

这次的情况有点特殊:

  1. 如何部署到 Azure Container Apps上,并且让这个容器可以与 Azure 内的某虚拟机内网互通?
  2. 在CPU使用率比较高的情况下,如何自动扩容?如果做不到这点那也没必要用托管k8s了呀

虚拟网络

通常来说,在 Azure 上的虚拟机,如果是同一个数据中心的,想要内网互通,直接都创建在一个虚拟网络下就可以了,默认情况下就是互通的,而且默认的安全组是允许同一个虚拟网络的通信的。

如果是不同的数据中心,或者不同的订阅,那么就要创建不同的虚拟网络,不同的网段,然后创建 peering

Azure Container Apps 连接到虚拟机并配置CPU自动缩放

创建的过程非常简单,鼠标点点下一步就可以了

Azure Container Apps 连接到虚拟机并配置CPU自动缩放

容器应用的虚拟网络

容器应用需要使用独享的虚拟网络,因此没法重复利用虚拟机已有的虚拟网络。

在创建容器应用时,选择数据中心,这里就建议就近选择啦。然后Container Apps Environment 点击create new

Azure Container Apps 连接到虚拟机并配置CPU自动缩放

在新的窗口中选择 Networking,配置自己的虚拟网络,如果你的容器不需要被访问,那么甚至可以选择 internal

Azure Container Apps 连接到虚拟机并配置CPU自动缩放

配置容器

下一步需要配置我们使用什么镜像

Azure Container Apps 连接到虚拟机并配置CPU自动缩放

需要注意的是 Command Override和Arguments Override这两个。Command Override并不是dockerdocker-compose中的command,比如你像 docker-compose.yml里这样写的

services:
  generic:
    image: ghcr.io/webp-pt/webplb:latest
    command: webplb -mode=worker -queue=generic

,把这个webplb -mode=worker -queue=generic复制到 Azure Portal上,那就错了……

  • Command Override:指的是ENTRYPOINT
  • Arguments Override:指的是 CMD 😢

那就简单了嘛!直接把 webplb -mode=worker -queue=generic 这一串粘贴到 Arguments Override的文本框,恭喜你又错了🎉。

因为,每一个参数都要用逗号和空格隔开,正确的形式是这样的

webplb, -mode=worker, -queue=generic

再接下来选择容器的配置,小到 0.25C 0.5G RAM,大到 4C 8G都在这里,如需环境变量也可以一起配置

Azure Container Apps 连接到虚拟机并配置CPU自动缩放

再下一步选择端口映射,一个是容器的一个是发布的端口

Azure Container Apps 连接到虚拟机并配置CPU自动缩放

创建的过程比较慢,大概要10-20分钟。如果你的应用有 ingress,那么还会看到一个 Application URL。

测试通信

容器创建好之后,在 Monitoring – Console 可以连接到容器,或者说是pod内部,之后可以用ping……嗯?😐 其实是通的,nc一下就知道了,我检查了很多地方也检查了安全组的ICMP配置,但是还是没法ping通不过就这样了吧😐

Azure Container Apps 连接到虚拟机并配置CPU自动缩放

配置缩放

http-scaler

通过http请求数量去扩容,实时的,默认就应该有这条规则,可以根据自身的情况进行配置。在满足条件时会自动扩容

Azure Container Apps 连接到虚拟机并配置CPU自动缩放

CPU使用率缩放

需要使用 Custom,azure使用的是KEDA, 在metadata中填入两个字段

  • type,有使用率Utilization和平均值AverageValue两种
  • value:值

比如下图的写法,就是CPU使用率超过80%就触发;内存也同理,只需要把cpu改成memory就可以

Azure Container Apps 连接到虚拟机并配置CPU自动缩放

缩放上下限

在这里可以配置缩放的上下限,上限是1000,下限……可以选择0。

Azure Container Apps 连接到虚拟机并配置CPU自动缩放

对于 Container Apps来说,最低副本数量是可以为0的。这意味着,如果你的网站没有收到任何流量或请求,ACA 将会自动缩减到零副本,从而节省资源。

当然这样有一定的冷启动时间……所以如果希望长时间运行,可以改成1或者任何合适的数值。

需要注意的是,缩放出来的新的容器的配置,都和最开始创建时配置的是一样的哦。

默认缩放行为

轮询间隔30秒(KEDA),冷却期300秒。这些参数无法改动。

重新部署

如果镜像更新了,或者需要更改配置,在 Azure Portal上也可以轻松完成

Containers – Edit and deploy 在下面container image这里就可以重新配置了,包括环境变量在内。

当然了懂得都懂,一个pod可以包含多个container,这里也可以加另外一个container的。

Azure Container Apps 连接到虚拟机并配置CPU自动缩放

最终结果

Azure Container Apps 连接到虚拟机并配置CPU自动缩放

这我是没想到的!

在急需扩容的时候,我的代码却出了问题,导致程序直接卡死并不退出,无法触发扩容规则🤡

参考文档

在 Azure 容器应用中设置缩放规则 https://learn.microsoft.com/zh-cn/azure/container-apps/scale-app?pivots=azure-portal

Scaling options in Azure Container Apps https://techcommunity.microsoft.com/t5/apps-on-azure-blog/scaling-options-in-azure-container-apps/ba-p/3878282


文章版权归原作者所有丨本站默认采用CC-BY-NC-SA 4.0协议进行授权|
转载必须包含本声明,并以超链接形式注明原作者和本文原始地址:
https://dmesg.app/aca-vm-scale.html

使用 Cloudflare Worker获取图片元数据

2024-09-28 17:56:24

这篇文章在 2024年10月05日23:31:04 更新了哦~

WebP Cloud 提供一个接口,可以用于获取图片的元数据,比如长宽、大小、色彩空间以及blurhash。这部分计算,尤其是blurhash其实还是略有压力的,我们就想能不能把这部分功能放到回源请求上。

对于 Azure Function来说,这必然不是问题,因为他几乎就是一个完整的NodeJS环境,可以用sharp的;但是对于Workers,由于他是V8,只支持NodeJS最基本的一些API,最多带上Wasm,这样用sharp就变成了几乎不可能的事情,因为要调用libvips。

最终经过了我的艰苦探索,发现一个名为 @cf-wasm/photon 的库,可以用来获取图片基础信息。首先需要 import

import { PhotonImage, SamplingFilter, resize } from '@cf-wasm/photon';

用起来也还行,首先我们需要通过 fetch获取图片,得到一个response,可以从这里拿到 ArrayBuffer

const response = await fetch(url)
const buffer = await response.arrayBuffer();

然后PhotonImage 需要Uint8Array,那先转换一下

const inputBytes = new Uint8Array(buffer);

然后加载图片

const inputImage = PhotonImage.new_from_byteslice(inputBytes);

宽高可以用 inputImage.get_width()inputImage.get_height()

色彩空间可以用 inputImage.get_image_data().colorSpace

文件大小直接 buffer.length就行

计算 blurhash建议先调整图片大小,毕竟 Worker有执行时间限制

const resized = resize(inputImage, 32, 32, SamplingFilter.Nearest);

然后计算

const blur = encode(resized.get_raw_pixels(), resized.get_width(), resized.get_height(), 4, 4);

至于图片格式,那只能靠magic header了,比如使用如下ChatGPT给我的神奇代码

function getImageFormatFromArrayBuffer(arrayBuffer) {
	const uint8Array = new Uint8Array(arrayBuffer);

	// Check for PNG (first 8 bytes: 89 50 4E 47 0D 0A 1A 0A)
	if (
		uint8Array[0] === 0x89 &&
		uint8Array[1] === 0x50 &&
		uint8Array[2] === 0x4e &&
		uint8Array[3] === 0x47 &&
		uint8Array[4] === 0x0d &&
		uint8Array[5] === 0x0a &&
		uint8Array[6] === 0x1a &&
		uint8Array[7] === 0x0a
	) {
		return 'png';
	}

	// Check for JPEG (first 3 bytes: FF D8 FF)
	if (uint8Array[0] === 0xff && uint8Array[1] === 0xd8 && uint8Array[2] === 0xff) {
		return 'jpeg';
	}

	// Check for GIF (first 6 bytes: GIF87a or GIF89a)
	if (
		uint8Array[0] === 0x47 &&
		uint8Array[1] === 0x49 &&
		uint8Array[2] === 0x46 &&
		uint8Array[3] === 0x38 &&
		(uint8Array[4] === 0x37 || uint8Array[4] === 0x39) &&
		uint8Array[5] === 0x61
	) {
		return 'gif';
	}

	// Check for BMP (first 2 bytes: 42 4D)
	if (uint8Array[0] === 0x42 && uint8Array[1] === 0x4d) {
		return 'bmp';
	}

	// Check for WebP (first 4 bytes: 52 49 46 46 and "WEBP" in bytes 8-11)
	if (
		uint8Array[0] === 0x52 &&
		uint8Array[1] === 0x49 &&
		uint8Array[2] === 0x46 &&
		uint8Array[3] === 0x46 &&
		uint8Array[8] === 0x57 &&
		uint8Array[9] === 0x45 &&
		uint8Array[10] === 0x42 &&
		uint8Array[11] === 0x50
	) {
		return 'webp';
	}

	return 'Unknown format';
}

部署

npm install @cf-wasm/photon
npm install blurhash
wrangler deploy 

就可以了。wrangler会自动打包,把依赖和wasm也一起上传上去

Azure Function

如果你使用的是Azure Function,那么事情就简单多了,直接安装并使用 sharp 就行。需要注意的一点是,Azure Function可以选择运行的环境是Linux还是Windows。所以本地也要安装好正确的sharp然后才可以部署。

npm install --cpu=x64 --os=linux sharp

详情可以参考Cross-platform

最终结果

需要注意 Workers 有内存限制,小心图片太大直接报错

原来是打算把 Worker和Function 用同一套代码库的,但是由于 Worker的限制,即使不同情况下使用不同的import,Worker还是没法兼容 Function🫠

所以只能分开两个分支了。

使用 Cloudflare Worker获取图片元数据

Cloudflare Workers 太弱智了,害我失去了人生中宝贵的三个小时使用 Cloudflare Worker获取图片元数据


文章版权归原作者所有丨本站默认采用CC-BY-NC-SA 4.0协议进行授权|
转载必须包含本声明,并以超链接形式注明原作者和本文原始地址:
https://dmesg.app/worker-image-metadata.html

将 Cloudflare Workers 迁移到 Azure Function

2024-09-27 14:18:33

WebP Cloud Services使用 Cloudflare Workers进行回源来保证原站服务器IP不泄漏。本着降本增效的理念,我们这次准备将部分回源请求迁移到 Azure Function。

Azure Function 同样也是由 Azure 提供的serverless服务,运行时可以使用 Python、NodeJS、Java和亲儿子 .NET、PowerShell,和 Cloudflare Workers一样,每个月前100万请求免费,具体信息可以参考价格表

我们的回源代码是使用 JavaScript写的,虽然这个语言挺扭曲的,但是为了方便迁移,就不变啦!

创建 Azure 账号

你需要有一个活跃订阅的Azure账号……

创建 Function

搜索栏搜索 Function App,点击 Create 按钮,会发现 Azure 提供了五种选项。选择第一个 Consumption

将 Cloudflare Workers 迁移到 Azure Function

基本信息

进入配置页面,可以新建一个资源组,需要选择的是 Runtime,这里选择 nodejs,然后 Region选择离用户最接近的地方。这里和 Cloudflare Workers不一样,Cloudflare Workers是在全球部署的,会在离用户最近的节点执行;Azure 这里是在固定的节点执行,所以对于大陆用户来说,日韩港新是比较不错的位置。

将 Cloudflare Workers 迁移到 Azure Function

存储

默认就行,要是看默认的名字不喜欢,可以自己改掉

网络

这里要选择Enable public access,要不然访问不了。

将 Cloudflare Workers 迁移到 Azure Function

其他选项

Monitoring 想开就开,为了省钱可以关掉。当然后续也可以重新开启;

Deployment是配置CD的地方,可以以后再配置

部署

部署完成之后 Azure 会提供一个URL,打开之后应该是这样的

将 Cloudflare Workers 迁移到 Azure Function

准备开发环境

不像 Cloudflare Workers 那么直接,开发 Azure Functions 最好用 VS Code。因为用 Azure Functions 扩展会很方便。

然后按F1弹出窗口 Azure Functions – Create New Project,语言就选择 JavaScript,愿意做类型体操也可以选择 TypeScript,或者任何你熟悉的语言都可以。

将 Cloudflare Workers 迁移到 Azure Function

Trigger为如何触发Functions,这个场景下选择HTTP Trigger就可以了

将 Cloudflare Workers 迁移到 Azure Function

熟悉开发环境

目录与文件

  • src/functions/fetchImage.js 这个就是你的代码
  • host.json:配置

部署

F1 – Deploy to Function App,选择订阅-刚刚创建的function

部署成功之后,浏览器访问:

https://blog-fun-post.azurewebsites.net/api/fetchimage

就可以看到 Hello World信息了。其中:

  • api是路由前缀,可以自定义的
  • fetchimage是代码里写好的路由,当然也可以自定义,默认代码里定义的name

Azure 上可以看到已经部署好的代码

将 Cloudflare Workers 迁移到 Azure Function

点进去终于有了和 Cloudflare Workers一样的在线编辑页面(不过可能是只读的,和选择的语言有关)

将 Cloudflare Workers 迁移到 Azure Function

本地调试

每次改代码都部署一次确实不是好办法。这个时候就要用本地调试啦,由于我们是用 HTTP trigger的,调试起来非常简单方便。哦对了,调试 JavaScript 应用得有nodejs

打开 fetchImage.js 按下F5,这里选择 Connect Storage Account(其实选择 emulator绕过去也行,没关系)

将 Cloudflare Workers 迁移到 Azure Function

如果是第一次运行,可能需要安装一些依赖,安装完成之后就会看到控制台输出了类似如下信息

Azure Functions Core Tools
Core Tools Version: 4.0.6280 Commit hash: N/A +421f0144b42047aa289ce691dc6db4fc8b6143e6 (64-bit)
Function Runtime Version: 4.834.3.22875
[2024-09-26T12:27:04.937Z] Debugger listening on ws://127.0.0.1:9229/882fb0c8-1957-4070-a6be-9cfd3250d77b
[2024-09-26T12:27:04.938Z] For help, see: https://nodejs.org/en/docs/inspector
[2024-09-26T12:27:05.003Z] Worker process started and initialized.
[2024-09-26T12:27:05.058Z] Debugger attached.
Functions:
fetchImage: [GET,POST] http://localhost:7071/api/fetchImage
For detailed output, run func with --verbose flag.

浏览器访问http://localhost:7071/api/fetchImage 就可以了,改了代码也会自动热加载,当然也可以打断点。

Functions

一个最简单的 Functions 代码是这样的

const { app } = require('@azure/functions');

app.http('fetch', {
	methods: ['GET', 'POST'],
	authLevel: 'anonymous',
	handler: async (request, context) => {
		context.log(`Http function processed request for url "${request.url}"`);
		return { body: `Hello hello hello` };
	},
});
  • app.http 的第一个参数是名字,要唯一,并且默认是路由
  • methods表示接受的请求方法
  • handler是处理请求的地方,第一个参数是request,可以用来获取请求体之类的信息,第二个是context,执行上下文,包括日志功能、绑定数据、环境信息等。
  • return 用于返回响应,按照文档 context.res 也应该可以,但是在我这里不行,可能需要额外配置一下。返回一个object,编辑器会自动补全,比如body, status,headers 等

定义路由

路由前缀

默认,functions的代码都是 在 /api 这个路由下的,在 host.json 里可以进行配置

"extensions": {
    "http": {
      "routePrefix": ""
    }
  }

这样就没有 api 这个前缀了,当然你也可以随便改!

路由名称

默认路由名称是app.http 的第一个参数,如

app.http('fetch', {
	methods: ['GET', 'POST'],
	authLevel: 'anonymous',
	handler: handler,
});

那么路由就是 fetch ,如果要自定义可以额外传入一个 route。需要注意不可以是空字符串,也不可以是/开头的

app.http('fetch', {
	methods: ['GET', 'POST'],
	authLevel: 'anonymous',
	handler: handler,
	route: "something"
});

根访问

如果你希望应用在 https://example.com 直接访问,不需要/api 也不需要路由名称,那么就要综合以上两种方法,配置前缀,然后 route: "/"不能留空😂,如果留空就会出现azure默认的页面

又一个人生小技巧🫠

迁移代码

我们的Cloudflare Workers代码是这么写的,非常简单

async function handleProxy(post_body) {
	const headers = {
		"Accept": post_body.accept,
		"User-Agent": post_body.user_agent
	};

	const response = await fetch(post_body.origin_url, {
		method: post_body.request_name,
		headers: headers
	});

	if (response.ok) {
		const res = new Response(response.body, {
			status: response.status,
			statusText: response.statusText,
			headers: response.headers
		});
		return res;
	} else {
		return new Response(response.statusText || "Unknown Error", {
			status: response.status,
			statusText: response.statusText
		});
	}
}

export default {
	async fetch(request, env, ctx) {
		try {
			const post_body = await request.json();
			return handleProxy(post_body);
		} catch (error) {
			return new Response("Invalid JSON data", { status: 400 });
		}
	},
};

基本上要改的地方如下:

  1. 入口参数位置调换
  2. 改改函数名字之类的

也就是改一下那个default

async function handler(request, context) {
	try {
		const body = await request.json();
		return handleProxy(body);
	} catch (error) {
		console.error('JSON parsing error:', error);
		return new Response('Invalid JSON data', { status: 400 });
	}
}

好了你的函数写好了,可以部署了。就是这么简单,除了配置环境那里麻烦点,别的都很容易,毕竟大家都是nodejs 20,自带了fetchResponse

甚至可以通过运行时信息不同,使用不同的入口函数,进而做到用一套代码。

总结

  1. Function提供的语言比Cloudflare Workers多
  2. 大家都是JavaScript,迁移很简单。为了类型安全也可以使用 TypeScript
  3. Function是区域性部署;Workers是全球部署且就近执行
  4. Function 想要做到就近执行,可能得需要配合 FrontDoor + 多地部署,想想就头疼
  5. Function提供的计划挺多的
  6. Function也应该可以拿来做一些奇奇怪怪的事情
  7. Azure的线路很好,对大陆访问非常友好,而Cloudflare则是降速CDN了
  8. Azure的功能好多(价格也很美丽),还待以后慢慢学习尝试

 


文章版权归原作者所有丨本站默认采用CC-BY-NC-SA 4.0协议进行授权|
转载必须包含本声明,并以超链接形式注明原作者和本文原始地址:
https://dmesg.app/workers-function.html