JavaScript未定义变量检测undefined null detection

HTML5自十多年前(2010年前后)被推举以来,逐渐大放异彩,尽管过去十年是属于Native APP的高光时刻,但HTML5的一些新特性和功能还是带来了大量的新网络/网页应用,尤其是在JavaScript的加持下,网页应用有极其令人着迷的便利与强大。

JavaScipt是网页应用默认编程语言,让人又爱又恨。

笔者曾经在《中国计算机学会通讯》上刊发了一篇看法文章《JavaScript或成主导的编程语言》( https://dl.ccf.org.cn/institude/institudeDetail?id=3738875941521408&_ack=1 ),其后两个开源项目 GTAjax ( https://ufqi.com/dev/gtajax )和 Hanjst ( https://ufqi.com/dev/hanjst/Hanjst.demo.html )又分别是使用JavaScript做了实现,甚至 Base62x( https://ufqi.com/dev/base62x/ ) 的编解码方法,都有JavaScript语言版本,可谓是JavaScript的重度用户、开发者。

即便如此“资深”,仍常常觉得JavaScript用起来让人不那么放心,为了写出更可靠的代码,我们甚至在JavaScript中显示地声明用严格检查模式: use strict.

即便如此“谨慎”,我们也会遇到 object/variable is null or undefined 的异常抛出,使得程序异常终止,为用户带来了很不好的体验。随着我们在 UfqiWork/有福工坊( https://ufqi.com/work ) 的开发推进,我们尝试寻找一种检测 JavaScript 变量或者对象是否null 或 undefined方法的努力,有了新收获,兹分享如下。

从JavaScript本身来说,要检测某个对象或变量是否为null/undefined,主要有两个工具可用: typeof 操作符 和 window.hasOwnProperty 方法。我们所创制的方法, 代码1,也是基于这两个基本操作。


//- _isDefined
//- @param: $var, to be tested;
//- @param: global_or_local: ‘global|local’, optional
//- return true | false
//- usage: test whether a global variable($var): _isDefined(“$var”) , _isDefined($var)
//- test a variable($var) declared nearby/locally: _isDefined($var) , _isDefined(“$var”, “local”)
function _isDefined($var, global_or_local){
var isDef = false;
if($var != null){
var myTp = typeof $var;
if(myTp == ‘string’){
if(window.hasOwnProperty($var)){
isDef = true;
}
else if(global_or_local != null && global_or_local == ‘local’){
isDef = true;
}
else{
//- @todo
}
}
else if(myTp != ‘undefined’){
isDef = true;
}
}
return isDef;
}


这些代码已经部署在 Hanjst/汉吉斯特, UfqiWork/有福工坊 相关模块中,经实测,运行良好,符合预期。

在编制这些代码之前,我们也曾经在多个应用中写了大量的检测某个JavaScript是否为null/undefined,无一例外地都是使用 typeof 或者 window.hasOwnProperty方法,甚至再带着对 null和 empty的判断。代码显得异常繁琐和臃肿。相信此后,这些代码将陆续得到简化和修正,新写的代码也将引入该功能 _isDefined .

在编制这些代码之前,我们也在网络上进行了 code review,翻阅了大量针对此问题的解决思路和办法,可能面对不同运行时环境,给出的解决方法也各个不同,实际上并没有一种方法可以通用到“放之四海而皆准”。

比如最接近本方法的一个尝试是定义一个 isDefined2, 代码2,然后在方法体内使用 typeof 操作符判断传入的 $var 是否 null/undefined , 以此来进行判断变量或者对象 $var 是否为 null/undefined .


//- _isDefined2,  WRONG!
//- @param: $var, to be tested
//- return true | false
function _isDefined2($var){
var isDef = false;
if(typeof $var != ‘undefined’){
isDef = true;
}
return isDef;
}


这段代码通常情况下,能够进行运行,并对一些变量实现null/undefined的探测。然而这个情况只局限在本地变量或者当前已经声明的变量,如果待探测的变量 $var 没有在 _isDefined2 调用之前被声明,则调用探测语句 _isDedined2($var) 本身就会报错说 $var is null/undefined .

问题进一步地被延申到 JavaScript的函数方法调用的参数传递是pass-by-value传值,还是 pass-by-reference传引用。通常情况下,JavaScript的方法调用都是 pass-by-value, 所以在执行语句  _isDefined($var) 时,先要对 $var 进行取值操作,而 $var 如果本身 undefined 时,悲剧错误就产生了,检测是否为 null/undefined 之前已经发生了 undefined .

当我们判断了 $var 为String类型的数据对象时,同时引发了另外一个问题,就是当某一个数据变量或对象其本身就是字符串时,如果其本身是一个本地变量,而String类型会被视为检测全局变量,这里就会发生异常错误,把本该返回本地变量为 true的结果,错误地解释为全局变量为 false。因此需要进一步地对方法本身做修正,使之能够兼容本地变量、String类型,改进的做法是针对 _isDefined 引入第二个参数,显示地告诉程序,当前虽然引入了 String类型的变量,但不是默认检测全局变量,而是要检测本地变量。

进一步地修正这个问题,我们创制了样例代码1. 可以兼容全局变量和本地变量,不管$var 是否被什么,都能够进行检测。只是,在调用的时候需要区分,待检测的变量或者对象是全局变量或者是局部变量:
如果是全局变量,调用方式是: _isDefined(“$var”) , _isDefined($var)
如果是局部变量,调用方法是: _isDefined($var, ‘local’) , _isDefined(“$var”, ‘local’) 

变量 $var 在被检测之前,我们能够知道它是全局变量或者局部变量吗?
答案应该是明确的。

测试样例:

var a;
console.log(“UfqiWork/Hanjst: a:”+_isDefined(a));
var b = null;
console.log(“UfqiWork/Hanjst: b:”+_isDefined(b));
var c = 0;
console.log(“UfqiWork/Hanjst: c:”+_isDefined(c));
console.log(“UfqiWork/Hanjst: global-c:”+_isDefined(“c”));
var dd = “d_string”;
console.log(“UfqiWork/Hanjst: local-dd:”+_isDefined(dd, ‘local’));
console.log(“UfqiWork/Hanjst: global-dd:”+_isDefined(dd));
console.log(“UfqiWork/Hanjst: global-dd:”+_isDefined(“dd”));
console.log(“UfqiWork/Hanjst: local-dd:”+_isDefined(“dd”, ‘local’));

预期输出:

UfqiWork/Hanjst: a:false
UfqiWork/Hanjst: b:false
UfqiWork/Hanjst: c:true
UfqiWork/Hanjst: global-c:false
UfqiWork/Hanjst: local-dd:true
UfqiWork/Hanjst: global-dd:false
UfqiWork/Hanjst: global-dd:false
UfqiWork/Hanjst: local-dd:true


Hanjst
Hanjst 汉吉斯特 Logo

🙋Hanjst汉吉斯特 是一种基于JavaScript的模板语言及模版解析引擎,她运行在客户端或服务器端。

🙋Hanjst汉吉斯特 能够表述逻辑控制,能够实现与服务器端模版语言相同的强大功能。

  • Hanjst当完全在客户端解析时,节省服务器端计算资源;

  • Hanjst模板语言独立,不与服务器端资源做任何绑定;

  • 纯粹的MVC,层间数据用JSON格式传递;

  • 常见模板语言功能全支持,附带复杂而强大的JavaScript编程能力;

  • 无学习成本,直接使用JavaScript书写模板语言;

  • ….

Hanjst is a JavaScript-based templating language and parsing engine that runs on both the client-side and/or server-side.

Hanjst can express logical controls and achieve the same functionalities as the server-side templating languages.

  • Hanjst’s Run-time in client-side, reduce computing render in server-side;

  • Hanjst is Language-independent, not-bound with back-end scripts or languages;

  • Totally-isolated between MVC, data transfer with JSON;

  • Full-support template tags with built-in logic and customized JavaScript functions;

  • No more tags languages to be learned, just JavaScript;

  • ….

发表在 -GTAjax, -Hanjst/-汉吉斯特, 编程技术, 计算机技术 | 标签为 , , , , | 4条评论

亮月亮科技Apache SoftwaresPdf DriveOpenAI ChatGPT

UfqiNews有福新闻更新:提质增效

上一次成批次地更新 UfqiNews有福新闻, 是在差不多两年前的《UfqiNews有福新闻的第N+1批次更新:清晰,流畅,省电》 ( https://ufqi.com/blog/ufqinews-updt-n-plus-1-fast-and-power-saving/ )。时间过得飞快,实际上 UfqiNews有福新闻 的优化和更新一直在持续,只是短期内大面积的更新,我们才会单独写一篇更新Blog一记录备查,就像接下来这篇改进的描述与说明一样。

1. 延长页面驻留在 UfqiNews有福新闻系统的时间

所面临的问题是,当某些页面依据系统的默认驻留时长到期后被移除,已经被某些外部资源所引用,被移除后的页面仍有访问流量进入。此时就会产生不好的用户体验,用户遭遇 404 页面找不到的情况,极大的浪费多种资源。

有鉴于此,我们通过升级设备运算和存储能力,进一步延长单个资讯页面在系统中的驻留时间,增加了约100%的时长。此举有望减少用户遭遇 404 页面找不到的几率。

2.改进持久永久固定链接的构成部分

如前所述,虽然延长了页面在系统的驻留时间,但仍不可避免的会有少量用户还是会遭遇 404页面找不到的情况。

为进一步解决这个问题,我们同时修改了持久/永久链接的构成部分:在页面固定链接中增加keyWord id。
修改前的页面固定链接: https://ufqi.com/news/page.4343804.html 
修改后的页面固定链接: https://ufqi.com/news/list.1327,187,4419.4343804.html

此举的目的在于,如果因为时间久远,某个页面被系统移除后,根据页面的固定链接,仍能够通过3个左右的关键词来提供几乎相同的内容给用户选择,避免用户打开“答非所问”的页面,或者遭遇 404的情况。

3. 每用户点击额外增加页面驻留时长30天

通过改进程序,增加对被阅览的资讯内容给予更多的驻留时长,让用户的流量来决定某一页资讯内容在系统中的最长寿命。

比如设定算法,某页资讯内容,如果每一个用户的一次点击可以给予30天的时长延续。如此以来,系统中会积淀大量由用户选择的优质内容,久而久之,系统形成正向反馈,越多的用户选择了越多的优质内容,越多的优质内容会吸引更多的用户。

假以时日,UfqiNews有福新闻 将成为中文资讯的一座宝库。那些生生不息的优质内容不断地由用户的一次次点击为其“续命”,直到永久。

4. 增长对资讯摘要的索引内容

根据前端阅读体验,我们适当地增长了对单条资讯的索引内容,大约增长了30%左右。

通过对索引内容的增长,前端用户有望看到更多的资讯细节,有助于用户进一步地的判断是否需要跟进深入阅读全部内容。

5. 通过NLP相关技术改进资讯内容的断句

改进内容分析算法,通过NLP(自然语言处理,Natural Language Processing)相关技术,实现对资讯内容句法分析,优先在整句断开(句号、问号等),其次在半句断开(逗号,分号等)。

结合与 4. 增长摘要的索引内容,用户在前端的浏览体验会更好,不会再看到在半句中间断开的情况。

6. 通过NLP相关改进分词引擎

通过优化升级中文分词引擎,改进分词取词范围(增加对人名、地名和机构名的收录、聚合),增加数组新词汇;

改进对所选择的词汇的权重值的调整,让存储和计算词汇权重值的效率更高。

此外,规划功能增补to-do list:

  1. 浏览历史
  2. 浏览排行榜
  3. 评论排行榜

 


ufqinews logo
有福新闻 UfqiNews

这里呈现热点全局, 尺寸间一览所有令人关注的疑点焦点;
这里表达条分缕析, 视野内一睹各个脉络清晰的故事主线.

有福新闻UfqiNews 带来全新的资讯阅览体验, 不信息过载, 亦不信息茧房.

在寻求最大社会共识和满足千人千面之间谋取平衡,
在满足广泛涉猎与追求术业专攻之间谋取平衡.

媒介插上人工智能的翅膀将如虎添翼, 与资讯比翼双飞.
新闻爱好者的良心之选, 匠心之作.

UfqiNews presents the hot spots globally, with all interesting points at a glance.
Information is organized here and there is a clear storyline within every single detail.

UfqiNews brings a brand new reading experience, no information overload and no information Cocoons,

In seeking a balance of the maximum social consensus and meeting thousands of people for each interest,
In achieving a balance between satisfying a wide range of hunting and pursuing specialization in the industry.

That media is being born with wings of the artificial intelligence will be even more powerful and the information will fly swifter than ever.

Better choices of newsreaders and the art of work from them.

发表在 UfqiNews有福新闻, 服务器运维, 社会生活, 编程技术, 计算机技术 | 标签为 , , , | 3条评论

老板选址BossXuanzhiUfqiFina有福金融UfqiWork有福工坊UfqiNews有福常在

gmt, utc, timezone, daylight saving,时区和夏令时

在阿里巴巴的Java编程规范中,有一条推荐是:
13. 【推荐】前后端的时间格式统一为”yyyy-MM-dd HH:mm:ss”,统一为GMT。

( https://ufqi.com/news/ulongpage.1524.html?tit=Java開發手冊-阿里巴巴-嵩山版-11:前后端规约 )

其中的重点是“统一为GMT”, 可以设想作为跨国集团企业,由于有多个时区的在线作业系统,如果不统一时区,各个需要通信的服务器之间会乱成啥。两个都是八点服务器可能一个是早上八点,一个晚上八点,还可能是前一天的八点,或者后一天的八点

服务器之间要统一时间和时区,客户端和服务器之间也需要统一时间/时区,有些对时间敏感的通信需要验证时间,如果只报时间是八点是远远不够的。这可能是阿里巴巴在Java编程操作手册中推荐这条规约的原因之一吧。

所以跨国集团企业的服务器时间必须统一,为啥“统一为GMT”呢?

GMT 是时区timezone序列中唯一不受夏令时/冬令时/日间灯节约时间调整的时区。与之对应的是 UTC,但UTC不是时区timezone的概念

不独在Java编程规范中需要注意时间和时区的问题,在其他编程语言中,也需要注意。比如PHP中,

# standard timezone with winter or summer time
date_default_timezone_set(“Europe/London”);
# standard timezone without winter or summer time 
date_default_timezone_set(“GMT”);
# non-standard timezone, but compatible 
date_default_timezone_set(“UTC”); 

 这三个设置,在冬令时,返回的时间是一样的,但如果在夏令时,第一个返回的时间就与后面两个不一样了。

对应地,在Java编程中,除了在服务器层面设置timezone,也可以在代码层面设置运行时timezone的指定:

System.setProperty(“user.timezone”,  “Europe/London”);
System.setProperty(“user.timezone”,  “GMT+0000”);

Java JDK的相关说明: ( https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/TimeZone.html )The syntax of a custom time zone ID is:

 CustomID:
         GMT Sign Hours : Minutes
         GMT Sign Hours Minutes
         GMT Sign Hours
 Sign: one of
         + -
 Hours:
         Digit
         Digit Digit
 Minutes:
         Digit Digit
 Digit: one of
         0 1 2 3 4 5 6 7 8 9
 

Hours must be between 0 to 23 and Minutes must be between 00 to 59. For example, “GMT+10” and “GMT+0010” mean ten hours and ten minutes ahead of GMT, respectively.

当然,较好的设置timezone的方式是在服务器层面,在编程语言的配置文件中,比如 PHP中的php.inc 文件,或者 Java的Jvm参数方式:java -Duser.timezone=“Asia/Chongqing” 。

gMIS吉密斯( https://ufqi.com/dev/gmis/ )的头部运行时设置中,已经启用了将当前运行时环境的时区timezone设置为 GMT;
GWA2吉娃兔( https://ufqi.com/dev/gwa2/ )的头部运行时设置中,已经启用了将当前运行时环境的timezone时区设置为GMT。

美国人纳斯达克总是晚上开盘偷摸炒股?

-R/o2SR

发表在 -gMIS, -GWA2, 服务器运维, 编程技术, 计算机技术 | 标签为 , , , , , | 一条评论

UfqiFina有福金融UfqiWork有福工坊UfqiNews有福常在Google Books

☘ gMIS吉密斯升级:+xTree,+图片水印等批量优化改进

对资本家和企业家予以轻视,这是现在极普通的事情。人,总喜欢嘲笑比自己的境遇更好的人。

——米塞斯Mises :人的行为Human Action, https://ufqi.com/news/ulongpage.2418.html?tit=人的行为 Human Action-72:选择的过程

How many roads must a man walk down, Before they call him a man, … The answer is blowing in the wind…

—- Blowing in the Wind , Bob Dylan

☘ gMIS吉密斯持续更新改进,这可能是gMIS自10多年前被推出以来,改进最多的一次,或者是记录改动功能点最多的一篇Blog文章。其中既有新功能的增加,也有对问题Bug的修改,更有一些是将现有功能推高到一个新的水平。

建议gMIS老用户在合适的时候,安排升级更新。

gMIS 吉密斯 持续改进细节,备注列如下。

 1. xTree: 对无限宽度和深度的层级数据支持

如同我们在之前Blog:分类、层级与编码( https://ufqi.com/blog/classify-hierarchy-code/ )和  -gMIS更新: 自动层级目录( https://ufqi.com/blog/gmis-update-xdirectory/ )中讨论的一样,我们在层级目录数据中,既可能遇到有限宽度和深度的层级目录数据,如行政地区编码,也可能遇到无限宽度和深度的层级目录数据,如文件目录。或者区块链。在后一种数据结构中,我们无法提前预知在某一层级有多少并列项(宽度),也无法预知到底会有多少层级。

为满足这种数据结构,我们设计和实现了xTree的输入与输出功能模块,用于支持对这种只知道父节点数据结构。新增了 extra/xtree.php 和 class/xtree.class.php . 可以支持无限宽度和无限深度的目录数据类型。

这一新出炉的功能,已成功部署和应用在 Boss选址(老板选址, bossxuanzhi.com )项目 和 有福工坊( UfqiWork, ufqi.com/work )项目上。

2. 改进对 Preset环境变量的支持,pnskxxx=yyy
+ act/preset-vars.inc.php , 得益于我们所设计的功能强大的Page Navigator组件( https://wadelau.gitbooks.io/gwa2/content/ ),gMIS可以通过URL参数自动生成对应的查询SQL语句,在保护安全的同时也同时提供了便捷的数据查询功能。

其中通过 Page Navigator Search Key (pnsk) 方式可以在打开相应表单时,传入查询条件. 这次改进不但在查询读取时使用pnsk等传入条件,在新增记录等环节,也可以读取和使用pnsk代入的预置条件。

3. 改进对点选pickup支持:增加筛选条件
在此之前 pickup 点选时,总是全表扫描记录,并生成各种点选候选项。此次改进,将点选候选项中植入预置条件,使得点选候选项对当前结果集更加具有针对性。

4. class/gtbl, 改进 _fillThis 对环境变量的支持

5. comm/ido.js: 改进对 pnskxxx=yyy环境变量的支持
同2.和3.的改进,在前端页面控制处,也增加相应的前置条件的使用。

6. 改进对 extra/linktbl的支持,增加 linkfield2, linkfield3的扩展
标间嵌套式,默认情况下使用外键字段进行索引,本次升级改进,使用两个及以上的字段作为条件进行标间嵌套使用。

7. 1. 改进对 extra/xdirectory的支持,增加缓存功能
此前版本的设计中,没有考虑对读取目录进行缓存设置,这次改进针对目录类型数据在服务器端进行了缓存。使得数据处理速度更快!

7.2. 改进 extra/xdirectory的功能,增加按英文字母或中文拼音排序显示iname的功能
    class/xdirectory, +sortDir, +getChild, +sortByGbk
    inc/config, +character_code_for_sort,   ascii, gbk, utf-8, see extra/xdirectory, Sat May 22 18:26:20 CST 2021
这是本次改进的重要功能之一,gMIS中使用了很多目录类型的数据,目录类型的数据通常都需要按照层级进行安排,而如果利用层级进行安排,在相等层级下,无法进行二次排序,导致使用起来多有不便。

这次改进就是把数据先按层级进行组织安排,然后在相同层级内,再按字母或拼音进行排序。对于大大量级目录数据的使用,操作人员可以快速的按拼音或者字母进行选项定位,而不只是靠目录层级进行人工查找。

模块化设计,目标数据无关/独立,使得所有此类型的数据均可使用,默认生效。强烈建议升级,极大提升数据处理效率,降低操作人员工作负荷。

8. 改进关联菜单的动态参数支持
通过读取菜单表设计的动态参数,并追加到相应的关联菜单的链接上。

9. 改进 act/updatefield 的功能
    +修正bug,增加安全检查

10.1. 改进文件上传功能
    +增加在线资源地址的引用
针对文件上传只有本地文件的情况,gMIS增加了针对在线资源的支持,通过输入在线资源地址,如 http/https/ftp等协议的在线资源文件进行支持,允许作为上传文件的方式之一。

    +修正对上传文件的安全检查
修正对上传文件的安全检查,强化对文件名的正则匹配表达式的检查。

10.2 改进对文件类型字段isImg的判断
    +增加对包含问号?文件名的检查。

11. 改进对字段默认值的计算算法
   +修正将 field comment 误读为字段默认值的 MySQL 引用。

12. 改进对 comm/modulepath.inc 的支持
    +增加 dynamicpara 在导航路径中。

13. +class/WaterMark.class, 对常见的上传图片进行打水印操作
    配置文件 inc/config.class 中,增加设置开关:
    $conf[‘watermark_for_upload_image’] = “”; # whether to put wartermark onto uploaded image or not, leave blank
if not watermark needed, Fri May 28 11:27:44 CST 2021

基于PHP内建的GD库进行透明度较高的打水印操作。使得通过管控后台上传的本地文件上传发布后能够携带上专有标志的水印Mark。
通过在 inc/config文件中可以设置水印中的文字,如果留空则表示不需要水印操作。

水印操作对于保护自有图片等资源具有一定的作用。同时半透明、不规则图形、处于图片中间区域这些特征使得在不破坏原图的情况移除水印变得相对困难。这些在一定程度上给自有资源一些保护,同时也是对自有品牌的宣传。
互联网烧钱战争火拼10年

14. 修正工具箱函数 comm/tools.function 里的 startsWith 和 endsWith
    由原来过于严格地判断判断same value 并且 same type为相等 === , 改为只判断 same value相等 == ,使得相应函数表述意义更准确,修正了此前的bug。

15. 其他一些小的修正和改进。

—-

一个看似简单的管理信息系统软件,我们制作了也使用了10多年,依然是大幅度地改进和升级,其中既有对错误的订正,也有与时俱进地新功能的加入。其中的历程,正如文章开头的歌词所唱的那样,一个男人要走过多少崎岖坎坷路才能被称之为“男人”? 一个系统软件要经过个日日夜夜的打磨,多少次的升级、改进和优化,才能被称之为一个“系统”?

操作系统微软视窗系统从3.x起,历经近30年,成为目前呈现在大众眼前的Windows 10.x。gMIS吉密斯已经多岁了,未来10年gMIS吉密斯会成长进化成什么样?
一起期待,共同打造。

—-

gMIS吉密斯,截至2021年6月份,累计更新了  379 commits,
每年大约34次成批次的更新,
除节假日外,平均几乎每周都有一次更新递交到代码库。


-gMIS (general Management Information System,吉密斯) 是一种基于 -GWA2 (General Web Application Architecture,吉娃兔,  ufqi.com/dev/gwa2 ) 的通用管理信息系统应用软件,具有可配置的输入和输出接口、开箱即用等特征。

可以在 gMIS吉米斯 上构建各种管理信息应用系统软件,例如:
内容管理系统(CMS), 客户资源管理(CRM), 企业资源计划管理(ERP),
办公自动化系统(OA)等,
也可以是各种行业应用管理系统软件,例如:
人力资源管理系统(HR),学生管理,档案管理,旅游管理,图书管理,
商品管理及业务运营支撑系统(BOSS)等等。
gMIS吉米斯 能够实现零代码开发、数分钟内快速搭建各种管理信息系统(MIS, Management Information System).

-gMIS is a -GWA2 based Management Information System (MIS) software with characteristics like configurable input and output interfaces, open-box-to-use.
Various management application software systems can be built on it, such as
Content Management System (CMS), Customer Resource Management (CRM), Enterprise Resource Planning Management (ERP),
Office automation systems (OA), as well as different industry application management system softwares, such as
Human Resource Management System (HR), Student Management, Archive Management, Tourism Management, Book Management,
Commodity management and business operations support systems (BOSS), etc.
With zero code development, -gMIS can build a set of management information systems (MIS) software in a few minutes.

Lower Costs, 
Better Productivity.
降低成本,
提高效率.

 https://ufqi.com/blog/gmis-updt-xtree/

-R/j2SS

发表在 -gMIS, 编程技术, 计算机技术 | 标签为 , , , | 留下评论

UfqiNews有福常在Google Books亮月亮科技Apache Softwares

Apache Tomcat: mod_jk 连接超时cping/cpong timeout

基于新版的Apache-2.4.46+和Tomcat-9.0.45+配置一例新的Web应用时,使用Mod_jk进行连接时,使用与之前版本相同的配置文件,各自运行起来后,Apache的JSP文件请求触发到Mod_jk并进一步地前传给Tomcat处理时,开始报错,报错信息是connection failed to backend service之类。

大致是Apache无法通过mod_jk连接到Tomcat的服务。而单独测试Apache的运行和Tomcat的运行,比如单独请求非JSP文件,或者在Tomcat的8080端口请求相应的JSP文件,均能够正常处理相应的请求。基于此,我们判断问题就出在mod_jk上,到底哪里出错了呢?

我们在 apache/conf/extra/httpd-jk.conf 中打开相应的详细日志记录。

# Our JK log level (trace,debug,info,warn,error)
JkLogLevel trace

输出所有步骤的过程记录。日志记录很快反馈回来,是无法连接到 ::1:8009 这个服务。

问题似乎一下子显现出来了。由于配置了IPv4和IPv6双栈网络地址,在一些服务层面对 localhost 的解析,可能是 ipv4地址:127.0.0.1 或者 ipv6地址 ::1 。可能由于某种原因,localhost 这个hostname在Apache的mod_jk中解析出是 ipv6地址,而Tomcat的程序中则解析出 ipv4地址。

相当于是mod_jk中的worker配置中: apache/conf/extra/workers.properties :

worker.balancer.balance_workers=node1
worker.node1.reference=worker.template
worker.node1.host=localhost 
#worker.node1.host=127.0.0.1
worker.node1.port=8009

这里启动后去连接 ::1:8009 服务, 而在 Tomcat中服务可能启动在 127.0.0.1:8009上,于是两边就这么因为ip地址的v4或者v6而错过了。问题若是如此,似乎也好解决:1)修改系统的hosts文件,修改消除主机名 localhost的歧义,只用在传统的127.0.0.1上,而针对 ::1 地址,另外命名为 localhost-ipv6;或者2)在Apache和Tomcat的配置文件中,不再使用主机名,都使用明确而具体的IP地址。 经过一番折腾,我们消除了 localhost的歧义,只指向 127.0.0.1, 同时在 Tomcat/conf/server.xml 中:

<Connector protocol=”AJP/1.3″
    port=”8009″
   address=”127.0.0.1″
   redirectPort=”8443″/>

也做了具体的IPv4地址的指定,这样按预期应该是能够连通的。
果然,经过这么一番操作,mod_jk不再报错说无法连接  ::1:8009 或者 127.0.0.1:8009的错误,但依然无法进行连接! 新的错误结果依然是 connection failed to backend service…. in error state or wrong port….

与此前所不同的是,这次明确显示出了 socket connected,连接已经被创建,不再是网络层的问题。这次的错误,增加了 timeout during cping/cpong …. ,根据这些新的报错信息,继续依靠搜索引擎的帮助,挖掘相关信息。
果然,已经有同学遇到类似问题,原来是由于 新版的Tomcat默认启用了新的配置,但未能在日志信息中给出具体而明确的指示。

-R/v2SS ) There was a change in Tomcat last year (from version 8.5.51 and version 9.0.31), which introduced a secretRequired attribute to the AJP connector with a default of true (cf. documentation). Hence you can either:

  • add a shared secret between the AJP connector and mod_jk

  • or add secretRequired="false" to the AJP connector.

直白地说,Tomcat-9.0.31+, 默认启用 secretRequired=true, 但在相应的样例配置默认设置中却没有提及。而且在错误日志中也没有提及是由于secretRequired的问题。要解决这个问题,就需要手工配置:1)增加一个共享的安全key在 AJP和mod_jk之间, 或者2)通过在AJP设置 secretRequired=false,停用这个功能。

奇怪的是这个AJP默认启用了secretRequired=true, 而 mod_jk 则是默认不启用,设置 secretRequired=false,两边自然就无法进行通信。遗憾 这样的错配,在软件层面发生了,而在错误信息里也指代不明,应该在后续予以修正。

发表在 服务器运维, 计算机技术 | 标签为 , , , | 一条评论

Apache SoftwaresPdf DriveOpenAI ChatGPT

一种便宜的数字化阅读的印版格式

新近在 有福常在(UfqiLong, https://ufqi.com/news/mod.ulong.html ) 转录一些中国传统经典作品(已进入公共版权)时,发现对传统作品的排版印刷,依然是较传统的版式。

这传统作品的版式,通常为一大段文字,其中夹杂有各种标点符号。密集的大段文字裹挟着各样的标点符号,这种版式的形成,可能有多种因素。最初,可能中文印刷等没有标点符号,一篇文章就是从头到尾的一串串字符。阅读及断句非常困难,好在当初这种制作也非常昂贵,小众,曲高和寡。

及至后来,有了低成本的印刷和功能丰富的标点符号,中文书籍才走入寻常百姓家。作为文化的载体,书籍在教化的同时,也承担了一部分娱乐的功能。如果从娱乐的角度去看,目前这种大段文字的版式,尤其是在电子屏幕上呈现出来,让人有种窒息的“密集”。

为改进 有福常在UfqiLong 的阅读体验,我们尝试使用一种新的,较便宜阅读和使用的版式对传统经典作品进行改版。比如我们将《红楼梦》( https://ufqi.com/news/ulongpage.1354.html )的章节改版成如下,将《金瓶梅》( https://ufqi.com/news/ulongpage.2186.html )的章节也取样如下。


UfqiContentFormater 改版红楼梦章节示例


UfqiContentFormater 改版金瓶梅章节示例

通过对上图左右改版前后的对比分析,直观感觉左侧传统版本很规整,通常一段较长,里面内容较丰富。右侧是使用 UfqiContentFormater进行改版后的效果,可以看得到,单个段落变短,段落数变多,行文句子不再那么工整,反而有些杂乱。然而下脚读进去,却是更容易切入,启停转合,更舒缓些。不会让人一口气读不下来,喘口气找不回歇点的“累”。

现在一些年轻人不爱读书,尤其是中规中矩的大部头,反而喜欢一些短小浅显的漫画、影视剧等,原因可能多种多样,其中之一或与版式沉闷,读起来“累”有关。
同样是经典电影,《十二怒汉》( https://ufqi.com/news/clscpage.1039.html )让普通观众看起来就有点“累”,单调的场景、严密的逻辑、环环相扣地推理,这些都需要开动脑筋全情代入进去才能继续。读一本书可能比看《十二怒汉》更累的就是要把文字转为“场景”,并全情代入。而这个场景转换,一千个人有一千个“哈姆雷特”,与看电影只有导演和编剧的“千人一面”不同,这就是读书的魅力吧。

有鉴于此,我们尝试将传统作品的版式做如下形式上的改版,使之更接近于“剧本”,以便于读者进行“场景”转换。
UfqiContentFormater 有福气内容格式化要义:
1) 段落之间用空白行隔开(留白),让读者“歇”一眼,类似WikiSource已经这么做了;
2) 单个段落长度控制在 600 – 900 字之间,太长不方便阅读,喘不过来气,太短了又零碎得像诗歌;
3) 单行字数,希望掌握在 150 字左右,太长了就换做2行,这也呼应Twitter等消息长度限制;
4) 直接引用的语句,带双引号的,后面需另起一行,不跟更多内容;
5) 段落首行适当缩进;
6) 其他一些辅助视觉识别的修饰。

使用这些格式化操作,通常会加长页数,书籍会变厚,好在是数字化阅读电子屏幕,并不会为此浪费更多的纸张。这样的便宜阅读体验,即使多翻页几次屏幕,也是值得的;有时候甚至不是翻页,而是滚屏几下即可。


试读一下不一样的,看看是否更容易上口。

https://ufqi.com/news/ulongpage.2558.html?tit=红楼梦-63:第60回 茉莉粉替去蔷薇硝 玫瑰露引出茯苓霜

https://ufqi.com/news/ulongpage.2545.html?tit=金瓶梅-100:第九十九回 刘二醉骂王六儿 张胜窃听陈敬济


一种便宜的数字化阅读的印版格式

发表在 社会生活 | 标签为 , , , | 一条评论

老板选址BossXuanzhiUfqiFina有福金融UfqiWork有福工坊UfqiNews有福常在