分类 Coding 下的文章

What is frp?

rp is a fast reverse proxy to help you expose a local server behind a NAT or firewall to the Internet. As of now, it supports TCP and UDP, as well as HTTP and HTTPS protocols, where requests can be forwarded to internal services by domain name.
frp also has a P2P connect mode.

github.com:frp

架构

FRP分为服务端frps和客户端frpc。架构如下:

设置服务端systemd service, /etc/systemd/system/frps.service:

[Unit]
Description=Frp Server Service
After=network.target

[Service]
Type=simple
User=nobody
Restart=on-failure
RestartSec=5s
ExecStart=/usr/bin/frps -c /etc/frp/frps.ini
LimitNOFILE=1048576

[Install]
WantedBy=multi-user.target

服务端设置好后:

Congratulations, frps install completed!
==============================================
You Server IP   : 123.123.123.123
Bind port       : 7020
Dashboard port  : 7500
vhost http port : 7080
vhost https port: 7443
Privilege token : tokenxxxxx!
Max Pool count  : 50
Log level       : info
Log max days    : 3
Log file        : enable

客户端 frpc.ini:

[common]
server_addr = 123.123.123.123
server_port = 7020

[web]
type = http
local_port = 80
custom_domains = frp.domain.com

nginx 代理:
server {

# 监听nginx 80端口
listen 80;
# 域名配置 记得一定要加上*.frp.xxx.com +  frp.xxx.com这个,只加frp.xxx.com是不行的,无法支持泛域名做sub模式
server_name *.frp.xxx.com frp.xxx.com;
location / {
    proxy_pass http: //127.0.0.1:7001;
    # 这个Host的header一定要加,不然转发后frp拿不到通过哪个域名访问的,导致转发失败
    proxy_set_header   Host             $host;
    proxy_set_header   X-Real-IP        $remote_addr;
    proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
}

}

参考

  1. FRP内网穿透与Nginx结合,实现多子域名转发服务(四级子域名)

《架构整洁之道》是Uncle Bob|Bob大叔【美】Robert C. Martin(罗伯特 C. 马丁)在2017年写的介绍软件架构的书。本书从最细节的编程范式,再讲到SOLID设计原则,然后依次介绍高阶的组件、软件架构。后面强调了数据库、框架、Web等是实现细节而非架构。最后则是其他人写的拾遗和半工作经历自传。整本书有点像搭建房子时介绍建筑架构,先从砖和钢筋混凝土到房价再到房子等由小到大介绍开了,很有趣。

作者总结了3种编程范式:

  1. 结构化编程:最传统的,程序是欧几里得公理系统;对函数控制权的直接转移进行了限制和规范;
  2. 面向对象编程:通过封装、继承和多态,对程序控制权的间接转移进行了限制和规范;
  3. 函数式编程:通过变量不可变(函数无状态)、对可变进行隔离,对程序中的赋值进行了限制和规范。

作者总结的架构精髓:SOLID原则,可以有效指导我们如何构建每一个程序模块。

S代表Single Responsibility Principle,即单一责任原则:每个模块都只有一个需要被改变的理由。据说与Conway Law直接相关。

O代表Open Close Principle,即开闭原则:允许新增代码来改变系统的行为,而不允许通过改变老代码来改变系统行为。Software entities (classes, modules, functions) should be open for extension but closed for modification

L代表Liskov Substitution Principle,李氏替换原则:组件之间必须满足设计约束才可以相互替换;派生类(子类)对象可以在程序中代替其基类(超类)对象。

I代表Interface Segregation Principle,接口隔离原则:客户(client)不应被迫使用对其而言无用的方法或功能。Clients should not be forced to depend upon interfaces that they don't use。接口隔离,避免不必要的依赖。

D代表Dependency Inversion Principle,依赖反转原则:高层次的策略性代码不应该依赖于底层的实现性代码,依赖关系应该反过来。例如业务逻辑不应该依赖UI或者数据库。High level modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions。

作者继续阐明组件构建原则。

组件定义:组件是程序部署的最小单元,即可执行文件和库,比如jar文件。

组件的聚合要满足以下三个原则:

  1. REP 复用/发布等同原则:软件复用的最小粒度应该等同与发布的最小粒度。这样任何变更不会导致过多的发布,或者过度的源代码修改。
  2. CCP 共同闭包原则:把那些会同时修改,并且为相同目的而修改的软件模块(类)放到同一个组件中去,即共同闭包。这实际是SRP在组件级别的重述,因为可维护性的重要性远大于可复用性。我们可以通过组件张力图,去计量共同闭包。
  3. CRP 共同复用原则:不要强迫一个组件的用户依赖他们不需要的东西。

组件的耦合应该满足下面三个原则:

  1. 无循环依赖原则:组件依赖关系中不应该出现环状结构。如果有,可以通过DIP解决。
  2. 稳定依赖原则:依赖关系必须指向更稳定的方向。被依赖的最多的组件应该是最稳定的,因为它难以被修改。计量关系:I = Fan-out/(Fan-in + Fan-out)。接口最稳定。
  3. 稳定抽象原则:一个组件的抽象化程度应该与其稳定性保持一致。

讲完组件,作者开始阐述软件架构。

主要是把策略和细节分离,在整个软件中,合理的划分边界,同时合理的规划好边界之间的依赖关系。同时做好策略与层次的设计:低层次的组件应该去依赖高层次的组件。

业务逻辑作为程序中最核心的用来挣钱/省钱的逻辑,应该位于层次同心圆最中间。而实现细节,或者I/O(UI、数据库等),则应位于最外面。依赖关系则是,最外面依赖最里面。
the clean artchitecture.jpeg

个人感觉,软件架构计时做好合理的分层,这里包括水平和垂直分层两个部分。水平只的是从UI、业务逻辑、持久化等数据流去分层;垂直分层则是从业务模块和领域的角度去分层,例如订单模块、CRM模块等。一个合理的软件架构,应该同时考虑这两种分层,并选择与之相应较好的侧重点。Salesforce是典型的侧重水平分层的平台,有明确的UI层(Visualforce Page、aura、lwc)、逻辑层(Apex)、数据层(SOQL、DML)。而目前流行的微服务架构,则更侧重垂直分层。

这两种分层的取舍,作者并没有过多解释,只是强调了策略与细节、分层与边界、分层与依赖等更加基础的内容。为什么?我猜是因为在架构上去侧重某种分层,结果就是出现框接,而作者认为框架是细节,并非架构。

作者还强调很多看起来像框架的东西,其实是实现细节

比如数据库、Web、应用程序框架,他们都是实现细节。

作者还对一个视频销售网站的架构设计,进行了精彩的讨论。

在另外一个人写的拾遗部分,主要讨论了作者的理论和自己的理解。

最后,作者回顾了从20世纪60年代到90年代,作者的软件工作生涯。可以从中看到作者不断总结教训经验,慢慢得出本书的这套理论。

参考

  1. douban 架构整洁之道
  2. wiki 开闭原则
  3. wiki 里氏替换原则
  4. wiki 接口隔离原则
  5. wiki SOLID
  6. zhihu 小话设计模式原则之:依赖倒置原则DIP
  7. The Clean Architecture

有时候我们需要在Salesforce页面下载存放为Attachment的文件;或者我们需要把存成Attachment的图片显示在页面上。

内部站点

如果我们文件为Attachment,在Salesforce Internal (即使用Salesforce账户登录的,非Digital Experience, Site.com),则可以使用

 <a href="{!URLFOR($Action.Attachment.Download, attachmentId)}">File Name</a>

下载文件。

或者使用

<img src="{!URLFOR($Action.Attachment.Download, attachmentId)}" />

显示图片。

如果是File,则可以使用Url.getFileFieldURL(entityId, fieldName)

Site.com

Site.com上的则不能用上面的方法,使用的话会直接报错。这时可以通过Salesforce提供的文件下载api /servlet/servlet.FileDownload?file=xxxx~18,不过要注意,一定要使用Salesorce Internal Url,使用Site.com的相关url肯定也会报错。

  1. 首先在后台获取 Salesforce Instance Url 或 Org Domain Url。例如:
    String orgUrl = Url.getOrgDomainUrl().toExternalForm()
  2. 将其传到前台,拼接成下载地址:
    <a href="{!orgUrl + '/servlet/servlet.FileDownload?file=' + attachment.Id}">File Name</a>

参考文档

  1. Visualforce Developer Guide: $Action
  2. Apex Reference Guide: URLClass
  3. stackexchange: How to get salesforce instance url
  4. Salesforce Developer Forum: Download Attachment from Sites??
  5. Salesforce Developer Forum: How to get downloadable link for attachment?

升级后打开前后端均显示503,查询nginx日志显示:

PHP message: Adapter Typecho_Db_Adapter_Mysql is not available

由于之前升级过PHP,因此估计是PHP的问题。修改Typecho的config.inc.php相关代码为:

/** 定义数据库参数 */
$db = new Typecho_Db('Pdo_Mysql', 'typecho_');

恢复正常。

Salesforce 未锁定包(Salesforce Unlocked Package)是Salesforce最新推广的基于包的开发最佳实践。通过Salesforce CLI,我们可以很方便的制作和部署未锁定包。本文只是简略的将核心步骤展示出来:

  1. 创建一个 SFDX 项目

    sfdx force:project:create -d demo-workspace -n expenser-app -p force-app
  2. 授权Dev Hub环境,该环境必须启用Dev Hub功能和未锁定包和第二代管控包功能

    sfdx auth:web:login -d -a devHub
  3. 创建一个草稿环境(scratch org)并在其中开发包

    sfdx force:org:create -f config/project-scratch-def.json -u scratchOrg1
  4. 保证所有要打包的组件都已经在当前的项目文件夹内
  5. 从 SFDX 项目文件夹,直接创建未锁定包:

    sfdx force:package:create -n "Demo App" -r force-app -t Unlocked -o [email protected]
  6. 检查项目文件夹中的sfdx-project.json文件,CLI 会自动更新项目文件,使其包含上一步创建的包的信息:

    {
    "packageDirectories": [
       {
          "path": "force-app",
          "default": true,
          "package": "Demo App",
          "versionName": "ver 0.1",
          "versionNumber": "0.1.0.NEXT"
       }
    ],
    "namespace": "",
    "sfdcLoginUrl": "https://login.salesforce.com",
    "sourceApiVersion": "50.0",
    "packageAliases": {
       "Expense Manager": "0Hoxxx"
    }
    }
  7. 创建一个包的版本,Salesforce CLI会自动处理包的版本号等

    sfdx force:package:version:create --package "Demo App" -k lushang.me --wait 10
  8. 在另一个创建好的草稿环境中,安装并测试这个版本的包:

    sfdx force:package:install -p "Demo [email protected]" -y testOrg1 -k lushang.me --wait 10 --publishwait 10
  9. 如果上一步骤没问题,则可以发布这个版本的包:

    sfdx force:package:version:promote -p "Demo [email protected]"

参考:

  1. Salesforce DX Developer Guide
  2. Workflow for Unlocked Packages
  3. Release an Unlocked Package