Category Archives: 技术

通过ssh tunnel和nginx从外网访问本地服务

在某些情况下, 需要让外网能够访问本地正在开发的网站, 例如做微信开发,微信API接受消息的url必须是外网可访问的地址,我们不可能每次修改代码再发布到外网服务器进行调试,通常可以通过ngrok来实现,使用ngrok就不需要拥有自己的外网服务器,但ngrok有时候还是有点慢, 而且每次地址都会变,当然也有国内的类似服务如natapp, natapp免费版本有各种限制,想想也不好用,虽然我也没用过。 但如果有一台外网服务器, 那么通过ssh tunnel和nginx就可以轻松实现从外网访问local的服务,这样就不用每次都发布到外网服务。下面将讲解如何实现。

前提条件:有一台外网可以访问的服务器

基本思路: 通过ssh建立一个通道,把远程外网机器上的一个端口和本地的端口建立起一个连接,远程机器机器上的那个端口的访问请求通过ssh tunnel转到本地机器的端口,而本地机器的这个端口也就是你web服务的端口,例如apache/tomcat/nginx的80或8080端口,这样就使得本地机器可在外网可以访问了

例如你的外网机器可以通过myhost.com访问(或者直接使用ip也可以),在本地机器运行如下命令:

ssh -nNT -R 8000:localhost:80 user@myhost.com
上面的命令就建立起了外网机器8000端口和本地机器80端口的通道,当访问外网机器8000端口时, 请求会被ssl tunnel转到本地机器的80端口,这样就已经实现了我们的目的,但是…
微信官方明确要求:
微信公众号接口只支持80接口
不知道为什么腾讯要做这个限制,但我们肯定不愿意一台机器唯一的宝贵80端口只用来做微信开发,好在nginx可以解决这个问题,配置如下:
server {
    listen 80;
    server_name myhost.com www.myhost.com;
    root /var/www;

    location /wechat/ {
        rewrite /wechat/(.*) /$1 break;
        proxy_pass http://127.0.0.1:8000;
        error_log /var/www/logs/wechat_error.log;
        access_log /var/www/logs/wechat_access.log;
    }
}
这样80端口还是可以用于其它的网站,url包含/wechat/的请求会被转到8000端口, 然后再转到本地机器的80端口, 在微信开发平台就可以大致设置url为http://myhost.com/wechat/receive, 相对应的本地localhost/receive用于接受微信的消息。
使用ssh tunnel和nginx相比于ngrok的好处有:
1. 如果是国内的服务器, 速度应该比ngrok快
2. 地址固定, 不会像ngrok那样每次都变,这样就省去每次都去微信开发平台设置url的时间,而且如果使用ngrok服务的话,通常需要点击好几次才能保存成功
补充:
上面的方法对微信消息的收发是没有问题的, 但对于微信网页开发就有一些问题了, 因为涉及到认证、url跳转, 静态资源(js/css/image)的访问,下面就这些问题提出一个更好的方案,那就是专门为微信开发新建一个二级域名,例如:wechat.myhost.com, 新建 nginx server如下:
server {
    listen 80;
    listen 443 ssl;
    ssl_certificate /usr/local/nginx/ssl/nginx.crt;
    ssl_certificate_key /usr/local/nginx/ssl/nginx.key;
    server_name wechat.myhost.com;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
    }
    error_log /mnt/www/logs/wechat_error.log;
    access_log /mnt/www/logs/wechat_access.log;
}
当然也得把那个二级域名加到本地机器的server name 里
server {
    listen 80;
    server_name wechat.dev wechat.myhost.com;
    ...

gem install – error : Connection reset by peer

sudo gem install cocoapods

ERROR:  Could not find a valid gem ‘cocoapods’ (>= 0), here is why:

          Unable to download data from https://rubygems.org/ – Errno::ECONNRESET: Connection reset by peer – SSL_connect (https://rubygems.org/latest_specs.4.8.gz)

上面这个错误可能是由于GFW引起了, 所以把source rubygems.org改成baobao.com就可以了

$ gem sources --remove https://rubygems.org/
$ gem sources -a https://ruby.taobao.org/
$ gem sources -l
*** CURRENT SOURCES ***

https://ruby.taobao.org

更多详情见 https://ruby.taobao.org/

php null empty

NULL

The special NULL value represents a variable with no value. NULL is the only possible value of type null.

A variable is considered to be null if:

  • it has been assigned the constant NULL.

  • it has not been set to any value yet.

  • it has been unset().


empty

emptyDetermine whether a variable is empty

Description

bool empty ( mixed $var )

Determine whether a variable is considered to be empty. A variable is considered empty if it does not exist or if its value equals FALSE. empty() does not generate a warning if the variable does not exist.

Returns FALSE if var exists and has a non-empty, non-zero value. Otherwise returns TRUE.

The following things are considered to be empty:

  • “” (an empty string)
  • 0 (0 as an integer)
  • 0.0 (0 as a float)
  • “0” (0 as a string)
  • NULL
  • FALSE
  • array() (an empty array)
  • $var; (a variable declared, but without a value)

LruCache为什么需要保存到RetainFragment, why need RetainFragment?

看了android 文档里的bitmapfun例子, 一开始怎么都不明白为什么需要把LruCache放到fragment里面, 后来再仔细回头看了看文档:

Runtime configuration changes, such as a screen orientation change, cause Android to destroy and restart the running activity with the new configuration (For more information about this behavior, see Handling Runtime Changes). You want to avoid having to process all your images again so the user has a smooth and fast experience when a configuration change occurs.

Luckily, you have a nice memory cache of bitmaps that you built in the Use a Memory Cache section. This cache can be passed through to the new activity instance using a Fragment which is preserved by callingsetRetainInstance(true)). After the activity has been recreated, this retained Fragment is reattached and you gain access to the existing cache object, allowing images to be quickly fetched and re-populated into theImageView objects.

 

原来当手机横竖屏变化时, activity会被销毁再创建,为了不丢失LruCache, 所以通过setRetainInstance(true), 保存了cache里的数据, 我就更疑惑了, 为什么不把LruCache设置成全局静态变量, 这样不是程序所有地方都可以共享地用到cache了吗