搞定了owncloud以及HTTPS的问题

其实还可以选nextcloud\seafile之类,后者还能支持分布式存储。

怕选择困难症,所以很快就定下来用owncloud,其中主要原因是它提供中文界面。

我本不需要,但如果要方便他人,必须有这个。

暂时不靠它存大文件,主要就是文档存储吧。

yum里有安装源,不过就是下载一堆PHP代码回来而已。

我一开始以为它安到哪里我就必须在哪里用,但发现apache的配置太麻烦,于是自作主张把它移到“合法”的位置,结果发现没问题,这就证明确实是一堆PHP页面没有其他的东西。就算有,其位置也不影响吧。

改了apache的配置之后,遇到几次权限问题。

其中有一个.ocdata的隐藏文件,死也搞不定。后来怀疑是owner的组有问题,照网上的脚本去设置,结果遇到脚本本身的问题,复制下来的脚本代码linux居然不认?仔细看报错,到处都是\r,想来应该是windows下的文本自带了不兼容linux的换行吧。

好吧,全部替换,第一次可行,可是配置不对,第二次又不可行了。后来想想不就是脚本吗?我就手动改好了。手动改掉了owner的group,这个group得是apache的拥有者。后来查了一下apache的进程信息,得到了真正有效的group,用命令改过果然就好了(用winscp是改不了的)。

这个owncloud也是讨嫌,官网不留APP下载地址,只留个google市场的地址。

在国内的安卓市场找到的版本过低,居然只能上传不能下载,也看不到远程的文件。后来到bing.com里下载到了新版本的安卓APP,用起来感觉还算好。

然后接下来发现不用https就不能分享文件。

好我继续搞https,之前有几个证书都过期了,更好理一理。

首先第一个问题,去年第一次过期的时候,把其中一个证书(第2个小程序的证书)给直接装到服务器里了,没有再走那个所谓的负载均衡,那么这个证书必须下载下来放到特定文件夹里,然后配合apache的配置文件来使用。更新完了之后果然好了。

第二个问题是最早那个小程序的证书问题,那个证书不需要自己折腾,直接部署到负载均衡上就行,可问题是以前行,现在不行了,折腾了老半天终于明白是监听器里没有绑定证书。也就是说不但证书要绑到负载均衡上,负载均衡的监听器也要绑证书。由此可知,一个负载均衡绑两个证书也是可以的,只要弄两个监听器就好了?不过既然之前已经自己在服务器上完成了https,那就不折腾了。

弄完证书之后,发现派的域名本身是没有https的,只好换一个有https的域名来访问,但这也不是访问的问题,还要修改config,而且是两条语句,修改完了之后就好了。

然而装到最后,突然想到自己的空间有限,搞这个也就是放放文档吧,如果改用seafile,还能玩分布式,凑一下应该挺好的。以后再说吧。

vbs调用系统api的终极办法

很多年前,我经常用vbs来做很多事情。

但那个时候调用一些外界api的时候都没有遇到问题。

之所以没有遇到问题是因为我没有调用系统的核心api,如今真要用系统api的时候,才发现原来不是那么容易。

又或者是因为当时我在借用excel内的vba来解决。

但现在遇到很多电脑真的没有装office,或者安了没有激活好。

所以必须脱离office来想办法。

发现原来有人早就想过办法。先是一个美国人搞出了一个dll来解决这个事。

后来这个美国人不玩这个了。

于是又有个叫Yuri Popov的俄罗斯人来解决这个问题,我们只要到他的主页去下载这个dll就可以了。
http://www.script-coding.com/dynwrapx_eng.html#download
使用方法可以看它的主页中的说明。

下面是一些例子:

如Beep的API声明为

Public Declare Function Beep Lib “kernel32″ Alias “Beep” (ByVal dwFreq As Long, ByVal dwDuration As Long) As Long

则使用方法如下

‘创建对象
Set Wrap = CreateObject(“DynamicWrapperX”)
‘注册API
Wrap.Register “KERNEL32.DLL”, “Beep”, “i=ll”, “f=s”, “r=l”
‘调用API
Wrap.Beep(500, 100)
其中注册API中, “i=ll”是API的参数类型, “f=s”是调用方式, “r=l”是返回类型
这些可以参考下面的说明。

REM i: (Argument Type)
REM ‘a’, sizeof(IDispatch*), VT_DISPATCH} // a IDispatch*
REM ‘c’, sizeof(unsigned char), VT_I4} // c signed char
REM ‘d’, sizeof(double), VT_R8} // d 8 byte real
REM ‘f’, sizeof(float), VT_R4} // f 4 byte real
REM ‘k’, sizeof(IUnknown*), VT_UNKNOWN} // k IUnknown*
REM ‘h’, sizeof(long), VT_I4} // h HANDLE
REM ‘l’, sizeof(long), VT_I4} // l long
REM ‘p’, sizeof(void*), VT_PTR} // p pointer
REM ‘s’, sizeof(BSTR), VT_LPSTR} // s string
REM ‘t’, sizeof(short), VT_I2} // t short
REM ‘u’, sizeof(UINT), VT_UINT} // u unsigned int
REM ‘w’, sizeof(BSTR), VT_LPWSTR} // w wide string

REM f: (Call Method)
REM ‘m’ – DC_MICROSOFT 0x0000, Default
REM ‘b’ – DC_BORLAND 0x0001, Borland compat
REM ‘s’ – DC_CALL_STD 0x0020, __stdcall
REM ‘c’ – DC_CALL_CDECL 0x0010, __cdecl
REM ‘4’ – DC_RETVAL_MATH4 0x0100, Return value in ST
REM ‘8’ – DC_RETVAL_MATH8 0x0200, Return value in ST

REM r: (Return Type)
REM Same as i
示例:

‘用机箱内的蜂鸣器播放音乐
Sub BeepMusic()
Set Wrap = CreateObject(“DynamicWrapperX”)
Wrap.Register “KERNEL32.DLL”, “Beep”, “i=ll”, “f=s”, “r=l”
res = Wrap.Beep(500, 100)
res = Wrap.Beep(550, 100)
res = Wrap.Beep(600, 100)
res = Wrap.Beep(650, 100)
res = Wrap.Beep(700, 700)
WScript.Sleep 200
res = Wrap.Beep(700, 100)
res = Wrap.Beep(650, 100)
res = Wrap.Beep(600, 100)
res = Wrap.Beep(550, 100)
res = Wrap.Beep(500, 700)
End Sub
BeepMusic
‘取前景窗体标题
Sub GetForeWindowCaption()
Const WM_GETTEXT = &HD
Set Wrap = CreateObject(“DynamicWrapperX”)
Wrap.Register “USER32.DLL”, “GetForegroundWindow”, “f=s”, “r=l”
Wrap.Register “USER32.DLL”, “SendMessage”, “i=lllr”, “f=s”, “r=l”
Title = Space(100)
res = Wrap.SendMessage(Wrap.GetForegroundWindow(), WM_GETTEXT , 100, Title)
GetForeWindowCaption = Title
End Sub
MsgBox GetForeWindowCaption
‘发送键盘消息,显示桌面
Sub ShowDesktop()
Const VK_LWIN = &H5B
Const VK_D = &H44
Public Const KEYEVENTF_KEYUP = &H2
Set Wrap = CreateObject(“DynamicWrapperX”)
Wrap.Register “USER32.DLL”, “keybd_event”, “i=ccll”, “f=s”
Wrap.keybd_event VK_LWIN, 0, 0, 0
Wrap.keybd_event VK_D, 0, 0, 0
Wrap.keybd_event VK_D, 0, KEYEVENTF_KEYUP, 0
Wrap.keybd_event VK_LWIN, 0, KEYEVENTF_KEYUP, 0
End Sub
ShowDesktop

不撞南墙心不死,一个multiparty花了二天时间没搞定

其实没什么,只是在小程序里做一个上传图片的功能。

前端用微信自己提供的上传控件。

后端用nodejs+express+multiparty

一开始的时候,我看网上说用connect-multipart,刚准备试一下,才发现这玩意已不被express推荐。

然后又看到有人说直接用bodyparse就可以了,结果发现新版本的bodyparse根本不支持multipart/form,不能用于上传文件。

然后就用了multiparty。

真是大坑啊。

由于我现在用了router,所以建立server的时候是在router前面就已经建了。

所以到了最终操作multiparty的时候,我只要New一个form就好了。

然后用form.parse来解析,发现没用,收不到文件。

于是跑去用multer,这个东西是express在文档里直接支持的,但是试了一下没效果。

这时翻回来用multiparty,在winscp刷新了一下,发现原来已经收到了N个文件,之前测试的时候留的,当时看不到,是因为winscp不刷新的话,即使打开一百次文件夹都看不到新文件。

这时才知道这玩意可以用。

大喜过望,但是可惜的是,form.parse里的callback没用,只有在一种情况下它起作用,那就是当创建form的时候路径写错了,就可以在callback里打印err.message。除此之外,是绝对没用的。

如果直接在form.parse后面写res.send来向前端返回数据,那么等于都不知道有没有上传成功就贸然回复。

后来看到有人说在express2和3里,bodyparse还能管着multipart/form类型,所以一定要把json和encode两种类型单独写,不要直接写一个app.use(bodyparse)。

但是我本来就没有这么写,所以这个答案对我没意义。

而且我用nmp list express查了一下,当前版本是4.x,在这个版本中bodyparse已经被阉割了。

不过我一直怀疑这个答案是最接近真相的,于是我把bodyparse给注释了,测试结果是:没用。

然后用bing查英文资料,有个老外说他遇到的问题是80k以上的文件就会无法进行form.parse,他的解决方案是用busboy,我不想就这么放弃,所以没采纳。

还有个老外也说有这个问题,但最后他自己说他是在两个地方多次require(multiparty)导致的,而且他建议我们不要用app.use,但我没这些毛病啊。

最后,终于找到一篇博客,这老外说express4下要用multiparty,但官方文档太简单了,没有卵用,所以他自己写了一个示例。

然后我照着他的示例终于拿到了fields。

因为他用到了一个我完全没想到的事件,form.on(‘field’,function(name,value){})

Multipart Parsing in Node.js Express 4

当然,他的写法事实上官方文档里也不是没有。

这种写法的思路是将autoFile设为false,从而能够得到part事件、close事件,自己处理文件流。

然而经测,part事件和close都没有触发。

结果就是,我可以拿到表单内容,也可以拿到文件,但是永远也无法知道文件的名称。因为文件名称是multiparty自己生成的临时名称。

其实办法不是没有,大不了我每次弄个临时文件来放文件,转移文件之后把文件夹给删了,每次一个文件,就不怕找不到文件夹,而且我还准备了一个更坑爹的做法,就是发两次请求,第一次把json发过来,用json中的名称建好文件夹等着它,然后第二个请求就对号入座。

但是真的不甘心啊,这也太麻烦了吧。

另外令我无语的是,form.on(‘field’,callback)会多次触发,有几个表单项就触发几次,而且我们可以想像的是,fields是收到请求立刻就被解析出来的,而文件什么时候收完,什么时候存储完成,这都是multiparty自己在后面黑着做的,既然form.parse自带的callback无效,那我还有什么办法呢?写一个定时器一直刷文件夹??

这个中间件明明是一个使用人数超多的产品,为什么我遇到这么大一个问题却找不到答案呢?

如果说我的代码写得有问题,那么应该收不到文件,或者拿不到field,但问题是两者都可以做到,真是要被它搞疯了。

如果按我的习惯,我是不会为这么一个中间件花这么多时间的,但是现在就是花了这么多时间,真是太扯了。

最后,我把官方文档又仔细看了一遍,终于把问题搞定了,Part事件就是当原始的请求来了一截之后就触发,当有一个field来了,它就会触发,有一个文件来了,它也会触发。

不过可惜的是,文件上传并不是一个连续的过程,而是分块的,而且好像微信默认就是分块的,结果而我现在的写法只能收到第一块,这一点可以从form.on(‘progress’,(bytesReceived, bytesExpected)=>{})得知,收是收了很多次,但是最后写成的文件只有第一次收的大小。

所以现在的问题就是怎么把20K以上的文件收完整。

现在收不完,close事件就永远也不会被触发。

不行只好读一下multiparty源码,看看它到底怎么回事。

 

nodejs接收post数据返回404的原因

真的是蠢爆了。

一般用原生的node或express写个单页面,是通过app.get/app.post/app.all来对get和post方法进行处理的。

用了路由,就是router.get和router.all/post什么的。

但我一开始并没有注意这router.get中的get其实是get方法,我一直以为get是只是router组件自带的一个什么配置方法。

所以复制的代码一直用的get。

后来把router.get改成router.all,立刻不再出现404了。

醉啊醉。

重拾小程序遇到的蛋疼问题集锦

话说又是几个月没动小程序了。

 

今天才发现无法鉴权,看了半天提示,一会儿说网络问题(确实遇到过网络问题,因为宽带断了),一会儿又502,一会儿又404,大部分情况下就是提示说鉴权服务器有问题。

其实这个提示是业务服务器提示的,但是因为它一会儿走socket一会儿走https,所以用fiddler老是抓不了包,导致我真以为是客户端开发工具升级导致的毛病,以为丫根本就没有联上网,盯着微信自己搞127.0.0.1的js看了半天(根本不可能看出什么鬼的,毕竟全是压缩过的代码,而且也没法打断点),天晓得控制台那一层层追的require是什么鬼。

后来突然fiddler又抓到包了,大概是走https的时候提示了证书问题,我允许了,这才发现小程序开发工具是上了网的。

好吧,去服务器看看。

从history里找以前查日志的路径,结果一找发现根本没有那些路径,我一开始以为是log文件夹被我删了,后来才想起来当时输入的路径也是错的,因为当时把业务服务器和会话服务器给搞混了。

其实腾讯官方这个wafer demo很蛋疼,小企业玩这个会话与业务分离的架构纯属无聊,何况我连小企业都不算。

当初搞的时候没有把人家的架构图看清楚,8月份看了一下,这回想起来了,那个负载均衡根本没有起什么分流的作用,只不过把请求转发给了业务服务器,业务服务器又让会话服务器做鉴权,所以应该先上业务服务器上看日志。

上去一看history,又回想起当初和腾讯那个工程师一起找问题的经过。于是用当时写的curl命令测试了一下会话服务器相关的页面,结果返回来的全是404,apache说没有object。

问题大概是找到了:

上次把国外服务器给停掉,一口气把各种玩意(包括这个博客)全都搬到国内来,在小程序的生产环境中配了一堆虚拟主机,这一配不要紧,原来小程序那个文件夹就404了。

一开始以为是权限问题,在httd-vhost.conf里写了一个全局的文件权限/跳转配置,没有用。

在业务服务器里用curl访问会话服务器,还是找不到相关的页面,后来一想,可不是找不到吗?其他的玩意全都成虚拟主机了,小程序的mina_auth作为第一个应用却无枝可依,就连根目录的Index.html也找不到。如果直接访问IP的话,会跳到这个博客首页上来,只好把小程序也给配成一个虚拟主机,配完再curl,果然有效。

但是这还不行,必须把sdk.config里的会话服务器地址给改掉,毕竟原来写的是ip加文件路径,现在既然成虚拟主机了,直接设成ip才符合逻辑,改完一重启,果然OK。

想来当初搬家之后好像确实没测试。但是话说昨天刚打开小程序的项目,似乎是可以登录的?

反正不管怎么说,这事是解决了。

有趣的是,服务器端的问题解决了,前端的问题好像也无医自愈了:

晚上刚打开开发工具的时候,报错说我那个全局变量没定义,难道是因为没有授权,连什么systemInfo都不让用?我当时想,不过就取个窗口宽高而已,怎么这么麻烦?没想到后端问题搞定,这个报错就直接消失了。

原本设想一天就把我想写的那个小程序搞定,现在只好又延期了。

这次跟上次一样,中途跑到小程序交流群去提问,屁用没有,最后还是自己解决了问题。

复习:jquery的each和map的用法和注意事项

用Jquery的each和map,主要是顺手方便。性能什么的就不要考虑了。

不过有些事情必须知道,each这玩意是可以改变数组的。

而map则可以创建另外一个数组,function你直接return一个值,它就变成了数组成员。

比如:

var ne=$(‘a.color-m’).map(function(){return $(this).attr(‘href’).split(‘id=’)[1]}).get().join(‘|’)

用这个方法可以在某个页面上抓取ID然后做成一个用|分隔的字符串。

chrome浏览器主页被sougo.exowangdan.com劫持怎么办

其实我已经忍了很久了。

chrome浏览器主页被http://sougo.exowangdan.com:6060劫持了几年了。

虽然没看出什么危害来,但是始终觉得不对劲。

今天找到一个简单的办法来解决它。

就是把chrome.exe改成fuck.exe

当然,你也可以改成fuckyou.exe

改成xx.exe都行。

总之让流氓找不到chrome.exe就行了。

不过这么干完了,自己改主页也改不了,根本没用,就是出新标签页而已。

但是把这个“新exe”的快捷方式给锁定到任务栏之后,从任务栏里启动就会按照设置里的主页显示了。

bing的妙用

这年头,科学上网真的很难。

然而我只是想上google看看技术文档,你狗日的死也不让我看。

我怎么办?

现成的链接,就是没办法看。

只好把这链接放到bing.com里搜一下,选cached,嗯,如愿以偿。

我就看个技术文档,我容易吗?

比管道命令更合适的vim组合操作

我们知道xargs命令是专业的管道命令,也就是说它可以比较灵活地把前面命令的输出作为后面命令的输入,好处是比较灵活,而且对于没有管道输入能力的程序它可以较好的处理,便于实现各种一行式操作。

但是当我们拿find\locate\xargs和vim一起用的时候,就会遇到严重的问题。

首先vim会警告你,输入不是来自键盘,然后你硬要用,OK。

vim拿到第一个参数,你编辑完,退出,就会发现终端完全没响应了,按键盘上任何东西都看不到输出,你还以为是命令卡死了,按什么退出组合键都没有。

 

你看到不你输入的命令。

这说明什么呢,说明终端的模式被破坏了,也就是说终端能看到输入的命令,是因为终端默认的配置是允许看到命令的,如果不允许,当然看不到。此时需要用如下命令修复:

stty echo

但这样是不是解决了问题呢?

很遗憾,删除键,也就是backspace不能用了,你按退格键,它会被显示为类似^?的东东。

需要用一个stty erase ^?来解决。注意,后面那个^?不是两个字符,而是用退格键输入得到的。

但是即使是这样,输出的样式也是乱七八糟的,总之用着很别扭。

不过stty有一个强大的参数sane,stty sane可以直到类似复位的作用,使得一切看起来都恢复正常,但这只是看起来正常而已。

所以很显然,有xargs配合vim是很危险的。

与其这样,不如直接引用命令来得方便,至少没有特别严重的副作用。

像这样:

vim `locate index.php`

纵然结果仍然是会提示你多个文件等着编辑,至少不会出现“死机”的假像