openresty开发系列40--nginx+lua实现获取客户端ip所在的国家信息

为了实现业务系统针对不同地区IP访问,展示包含不同地区信息的业务交互界面。很多情况下系统需要根据用户访问的IP信息,判断用户可能的访问区域,针对不同的区域提供个性化的服务内容。本方案在CentOS7.6环境下基于高性能的Openresty1.13.6.1来实现。

方案介绍

要通过IP地址确认归属地,通常可以使用一些在线查询服务来实现,但使用在线服务查询潜在存在性能问题,同时通过lua来访问外部服务增加额外的代码量。 通过本地的GeoIP库来实现查询是个比较好的方案,GeoIP提供免费和收费服务(https://www.maxmind.com/en/home),大多数情况下使用定期更新的GeoIP数据库能满足基本需求。

因此,可以在openresty中通过lua库本地GeopIP数据库的方式来实现快速位置查询和用户访问界面重定向。

环境准备

一:OpenResty安装

OpenResty方便地将Nginx和常用的各类lua库打包发布,可以方便地参考 https://openresty.org/en/installation.html 文档从源码编译安装。主要安装步骤说明如下:

tar -xvf openresty-VERSION.tar.gz
cd openresty-VERSION/
./configure -j2 --prefix=/usr/local/openresty
make -j2
sudo make install

# vim /etc/profile
export PATH=/usr/local/openresty/bin:$PATH

这里的VERSION 是OpenResty具体版本号,目前为 1.13.6.1,编译安装后可以通过如下命令查看版本信息:

[root@node5 conf]# /usr/local/openresty/bin/openresty -V
nginx version: openresty/1.13.6.1
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-36) (GCC)
built with OpenSSL 1.0.2k-fips  26 Jan 2017
TLS SNI support enabled
configure arguments: --prefix=/usr/local/openresty/nginx --with-cc-opt=-O2 --add-module=../ngx_devel_kit-0.3.0 --add-module=../echo-nginx-module-0.61 --add-module=../xss-nginx-module-0.05 --add-module=../ngx_coolkit-0.2rc3 --add-module=../set-misc-nginx-module-0.31 --add-module=../form-input-nginx-module-0.12 --add-module=../encrypted-session-nginx-module-0.07 --add-module=../srcache-nginx-module-0.31 --add-module=../ngx_lua-0.10.11 --add-module=../ngx_lua_upstream-0.07 --add-module=../headers-more-nginx-module-0.33 --add-module=../array-var-nginx-module-0.05 --add-module=../memc-nginx-module-0.18 --add-module=../redis2-nginx-module-0.14 --add-module=../redis-nginx-module-0.3.7 --add-module=../rds-json-nginx-module-0.15 --add-module=../rds-csv-nginx-module-0.08 --add-module=../ngx_stream_lua-0.0.3 --with-ld-opt=-Wl,-rpath,/usr/local/openresty/luajit/lib --with-pcre --with-http_gzip_static_module --with-http_realip_module --with-http_geoip_module --with-http_ssl_module --with-http_stub_status_module --with-stream --with-stream_ssl_module

openresty包含了自身的包维护工具opm,该工具采用perl实现依赖MD5,需要执行yum install  -y perl-Digest-MD5 安装

二:GeoIP2安装

1.从https://dev.maxmind.com/geoip/geoip2/geolite2/ 下载MaxMind格式的GeoIP2数据库保存到本地服务器,将数据库文件GeoLite2-City.mmdb保存到/usr/local/openresty目录下

2.GeoIP2 lua库安装,GeoIP2 lua库位于https://github.com/anjia0532/lua-resty-maxminddb ,可以通过如下命令方便安装:

# /usr/local/openresty/bin/opm get anjia0532/lua-resty-maxminddb

3.GeoIP2 lua库依赖动态库安装:lua库依赖libmaxminddb实现对mmdb的高效访问。需要编译该库并添加到openresty访问环境。
从https://github.com/maxmind/libmaxminddb/releases下载相应源码包到本地编译部署
基本编译步骤如下:

tar xf libmaxminddb-1.3.2.tar.gz
cd libmaxminddb-1.3.2
./configure
make
make check
make install
ldconfig

默认情况下上述操作会将libmaxminddb.so部署到/usr/local/lib目录下,为了让openresty访问,可以拷贝到openresty目录下,或通过如下步骤更新ldconfig。

sh -c "echo /usr/local/lib  >> /etc/ld.so.conf.d/local.conf"
ldconfig

三:配置openresty nginx环境。

1,配置openresty nginx加载相应的lua库和动态库,需要在http段添加如下指令,其中的;;表示默认库路径:

lua_package_path  "/usr/local/openresty/lualib/?.lua;;";
lua_package_cpath  "/usr/local/openresty/lualib/?.so;;";

2,指定lua处理请求的方式。 为了简易直观,如下示例的nginx.conf配置指定 /ipinfo 开始的url请求通过/usr/local/lua/getipinfo.lua脚本来处理,这里没有做其他复杂的请求和变量处理工作。
lua_code_cache off;参数只为测试使用,生产环境需设为on;

nginx.conf的server部分添加如下location:
    location /ipinfo {
                default_type "text/html";
                charset utf-8;
                content_by_lua_file  /usr/local/lua/getipinfo.lua;
        }

# 获取ip归属的lua脚本:

# vim /usr/local/lua/getipinfo.luangx.say("<br>IP location query result:<hr><br>")local cjson=require 'cjson'
local geo=require 'resty.maxminddb'
local arg_ip=ngx.var.arg_ip
local arg_node=ngx.var.arg_node
ngx.say("IP:",arg_ip,", node:",arg_node,"<br>")if not geo.initted() thengeo.init("/usr/local/openresty/GeoLite2-City.mmdb")
endlocal res,err=geo.lookup(arg_ip or ngx.var.remote_addr)if not res thenngx.say("Please check the ip address you provided: <div style='color:red'>",arg_ip,"</div>")ngx.log(ngx.ERR,' failed to lookup by ip , reason :',err)
elsengx.say("Result:",cjson.encode(res))if arg_node thenngx.say("node name:",ngx.var.arg_node, " , value:",cjson.encode(res[ngx.var.arg_node] or {}))endend

访问接口:
http://10.11.0.215/ipinfo?ip=120.76.101.211&node=city

IP location query result:

IP:120.76.101.211, node:city
Result:{"city":{"geoname_id":1808926,"names":{"en":"Hangzhou","ru":"Ханчжоу","fr":"Hangzhou","pt-BR":"Hangzhou","zh-CN":"杭州","es":"Hangzhou","de":"Hangzhou","ja":"杭州市"}},"subdivisions":[{"geoname_id":1784764,"names":{"en":"Zhejiang","fr":"Province de Zhejiang","zh-CN":"浙江省"},"iso_code":"ZJ"}],"country":{"geoname_id":1814991,"names":{"en":"China","ru":"Китай","fr":"Chine","pt-BR":"China","zh-CN":"中国","es":"China","de":"China","ja":"中国"},"iso_code":"CN"},"registered_country":{"geoname_id":1814991,"names":{"en":"China","ru":"Китай","fr":"Chine","pt-BR":"China","zh-CN":"中国","es":"China","de":"China","ja":"中国"},"iso_code":"CN"},"location":{"time_zone":"Asia\/Shanghai","longitude":120.1619,"accuracy_radius":50,"latitude":30.294},"continent":{"geoname_id":6255147,"names":{"en":"Asia","ru":"Азия","fr":"Asie","pt-BR":"Ásia","zh-CN":"亚洲","es":"Asia","de":"Asien","ja":"アジア"},"code":"AS"}} node name:city , value:{"geoname_id":1808926,"names":{"en":"Hangzhou","ru":"Ханчжоу","fr":"Hangzhou","pt-BR":"Hangzhou","zh-CN":"杭州","es":"Hangzhou","de":"Hangzhou","ja":"杭州市"}}

格式化输出:
{
    "city": {
        "geoname_id": 1808926,
        "names": {
            "en": "Hangzhou",
            "ru": "Ханчжоу",
            "fr": "Hangzhou",
            "pt-BR": "Hangzhou",
            "zh-CN": "杭州",
            "es": "Hangzhou",
            "de": "Hangzhou",
            "ja": "杭州市"
        }
    },
    "subdivisions": [{
        "geoname_id": 1784764,
        "names": {
            "en": "Zhejiang",
            "fr": "Province de Zhejiang",
            "zh-CN": "浙江省"
        },
        "iso_code": "ZJ"
    }],
    "country": {
        "geoname_id": 1814991,
        "names": {
            "en": "China",
            "ru": "Китай",
            "fr": "Chine",
            "pt-BR": "China",
            "zh-CN": "中国",
            "es": "China",
            "de": "China",
            "ja": "中国"
        },
        "iso_code": "CN"
    },
    "registered_country": {
        "geoname_id": 1814991,
        "names": {
            "en": "China",
            "ru": "Китай",
            "fr": "Chine",
            "pt-BR": "China",
            "zh-CN": "中国",
            "es": "China",
            "de": "China",
            "ja": "中国"
        },
        "iso_code": "CN"
    },
    "location": {
        "time_zone": "Asia\/Shanghai",
        "longitude": 120.1619,
        "accuracy_radius": 50,
        "latitude": 30.294
    },
    "continent": {
        "geoname_id": 6255147,
        "names": {
            "en": "Asia",
            "ru": "Азия",
            "fr": "Asie",
            "pt-BR": "Ásia",
            "zh-CN": "亚洲",
            "es": "Asia",
            "de": "Asien",
            "ja": "アジア"
        },
        "code": "AS"
    }
}
node name: city, value: {
    "geoname_id": 1808926,
    "names": {
        "en": "Hangzhou",
        "ru": "Ханчжоу",
        "fr": "Hangzhou",
        "pt-BR": "Hangzhou",
        "zh-CN": "杭州",
        "es": "Hangzhou",
        "de": "Hangzhou",
        "ja": "杭州市"
    }
}

线上环境获取客户端ip所在国家的示例:
nginx.conf主配置,引入ip库

[root@gdpr04:~]# cat /usr/local/nginx/conf//nginx.conf

#user  apache;
worker_processes  8;#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;#pid        logs/nginx.pid;
pid        /data/www/logs/nginx.pid;worker_rlimit_nofile  65535;events {use epoll;    worker_connections  10240;
}http {include       mime.types;default_type  application/octet-stream;#set_real_ip_from   0.0.0.0/0;#real_ip_header     X-Forwarded-For;#proxy_set_header   Host    $host;  #proxy_set_header   X-Real-IP       $remote_addr;  #proxy_set_header   X-Forwarded-For $http_x_forwarded_for;  #proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for; proxy_headers_hash_max_size 51200;proxy_headers_hash_bucket_size      6400;ssl_session_cache    shared:SSL:10m;ssl_session_timeout  10m;# fastcgi_cache_path /usr/local/nginx/fastcgi_cache levels=1:2 keys_zone=TEST:10m inactive=5m;    fastcgi_connect_timeout 300;    fastcgi_send_timeout 300;    fastcgi_read_timeout 300;    fastcgi_buffer_size 64k;    fastcgi_buffers 4 64k;    # fastcgi_busy_buffers_size 128k;    fastcgi_temp_file_write_size 128k;    # fastcgi_cache TEST;    #fastcgi_cache_valid 200 302 1h;    #    fastcgi_cache_valid 301 1d;    #fastcgi_cache_valid any 1m; #    fastcgi_cache_min_uses 1;#geoip_country   /usr/local/nginx/conf/GeoIP.dat;#fastcgi_param   GEOIP_COUNTRY_CODE $geoip_country_code;geoip2 conf/GeoIP2/GeoIP2-Country.mmdb {auto_reload 5m;$geoip2_metadata_country_build metadata build_epoch;$geoip2_data_country_code source=$remote_addr country iso_code;$geoip2_data_country_name country names en;}geoip2 conf/GeoIP2/GeoIP2-City.mmdb {$geoip2_data_city_name  city names en;}fastcgi_param COUNTRY_CODE $geoip2_data_country_code;fastcgi_param COUNTRY_NAME $geoip2_data_country_name;fastcgi_param CITY_NAME    $geoip2_data_city_name;open_file_cache max=204800 inactive=20s;open_file_cache_min_uses 1;open_file_cache_valid 30s; #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '#                  '$status $body_bytes_sent "$http_referer" '#                  '"$http_user_agent" "$http_x_forwarded_for"';#    log_format main '[$time_local] $remote_addr $status $request_time $body_bytes_sent "$request" "$http_referer" $upstream_addr $http_x_real_ip $http_x_forwarded_for $http_user_agent  $request_filename';log_format main  '$remote_addr - - [$time_local] - - "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $request_time '; #   log_format test '[$fastcgi_script_name] [$time_local] $remote_addr $status $request_time $body_bytes_sent "$request" "$http_referer" $upstream_addr $http_x_real_ip $http_x_forwarded_for $http_user_agent ';log_format error  '$remote_addr - - [$time_local] - - "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $request_time '; #access_log  logs/access.log  main;sendfile        on;tcp_nodelay    on;keepalive_timeout  70;#----for upload fileclient_max_body_size    8M;client_body_buffer_size 2M;#--- for resolve 400 errorclient_header_buffer_size 64k;large_client_header_buffers 4 64k;proxy_connect_timeout 60s;proxy_read_timeout 60s;#60s内后端服务器需要返回成功proxy_send_timeout 60s; proxy_buffer_size 16k;proxy_buffers 4 32k;proxy_busy_buffers_size 64k;proxy_temp_file_write_size 64k;gzip  on;gzip_vary off;gzip_min_length  1k;gzip_buffers     4 16k;gzip_http_version 1.0;gzip_comp_level  3;gzip_disable     "MSIE [1-6]\.";gzip_types text/plain text/css text/javascript application/x-javascript text/xml application/xml;fastcgi_intercept_errors on;ssi on;ssi_silent_errors on;#ssi_types text/shtml;expires 30d;server_names_hash_bucket_size 20480;#if_modified_since before;#limit_req_zone $binary_remote_addr zone=all_zone:10m rate=3r/s;#limit_req zone=all_zone burst=2 nodelay;limit_req_zone $binary_remote_addr $host $request_uri zone=all_zone:30m  rate=4r/s;geo $white_ip {ranges;default 0;1.1.1.1-1.1.1.254 1;192.168.254.1-192.168.254.254 2;}limit_req_whitelist geo_var_name=white_ip geo_var_value=1;limit_req_whitelist geo_var_name=white_ip geo_var_value=2;limit_req_whitelist geo_var_name=white_ip geo_var_value=3;limit_req_whitelist geo_var_name=white_ip geo_var_value=4;limit_req_whitelist geo_var_name=white_ip geo_var_value=5;limit_req_whitelist geo_var_name=white_ip geo_var_value=6;#    upstream php_pool{# ip_hash;#        server unix:/tmp/php-cgi.sock;#       server 192.168.254.126:9000 max_fails=0 fail_timeout=30s weight=3;#        keepalive 32;#        keepalive_timeout 30s;#        check interval=3000 rise=2 fall=5 timeout=1000 type=tcp port=9000;#        check_keepalive_requests 100;#        check_http_send "HEAD / HTTP/1.1\r\nConnection: keep-alive\r\n\r\n";#        check_http_expect_alive http_2xx http_3xx;#    }include vhost.d/*.conf;server {listen       80 default_server;server_name  localhost;location / {root   /data/www/html;index  index.html index.htm;}error_page   500 502 503 504  /50x.html;location = /50x.html {root   html;}location /ws_status {stub_status on;access_log off;}}
}

# 具体vhost的配置
# cat country-info.chinasoft.com.conf
server {listen 80;server_name       country-info.chinasoft.com ;#access_log      /data/www/logs/nginx_log/access/country-info.chinasoft.com_access.log main ;#error_log       /data/www/logs/nginx_log/error/country-info.chinasoft.com_error.log ;root            /data/www/vhosts/common-info.chinasoft.com/httpdocs ;index           index.html index.shtml index.php ;error_page  404 403             /404.html;location /api/v1/checkeu {add_header 'Access-Control-Allow-Origin' '*';add_header 'Access-Control-Allow-Credentials' 'true';add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';default_type 'text/plain';content_by_lua_file '/usr/local/nginx/conf/vhost.d/checkeu.lua';}}server {listen 443;ssl on;ssl_certificate         /usr/local/nginx/conf/cert2016/iskysoft_com.crt;  ssl_certificate_key     /usr/local/nginx/conf/cert2016/iskysoft_com.key;ssl_session_timeout     5m;ssl_protocols   TLSv1 TLSv1.1 TLSv1.2;ssl_ciphers     "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!AES128-GCM-SHA256:!AES256-GCM-SHA384:!AES128-SHA256:!AES256-SHA256:!AES128-SHA:!AES256-SHA:AES:!CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA";ssl_prefer_server_ciphers       on;server_name     country-info.chinasoft.com;access_log      /data/www/logs/nginx_log/access/country-info.chinasoft.com_access.log main ;error_log       /data/www/logs/nginx_log/error/country-info.chinasoft.com_error.log ;root            /data/www/vhosts/common-info.chinasoft.com/httpdocs ;index           index.html ;error_page  404 403             /404.html;location /api/v1/checkeu {add_header 'Access-Control-Allow-Origin' '*';add_header 'Access-Control-Allow-Credentials' 'true';add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';default_type 'text/plain';content_by_lua_file '/usr/local/nginx/conf/vhost.d/checkeu.lua';}
}

# 获取国家的lua脚本
# cat /usr/local/nginx/conf/vhost.d/checkeu.lua

--ngx.say(" {\"c_type\":0}")
local ngxmatch=ngx.re.match
usercountry = ngx.var.geoip2_data_country_code
--usercountry = ngx.var.geoip_country_code
eopcountry = "AT|BE|BG|CY|HR|CZ|DK|EE|FI|FR|DE|GR|HU|IE|IT|LV|LT|LU|MT|NL|PL|PT|RO|SK|SI|ES|SE|GB"
if not usercountry thenusercountry = ''
endif not usercity thenusercity = ''
end
if ngxmatch(usercountry,eopcountry,"isjo") thenngx.say("{\"c_type\":1,\"country_code\":\""..usercountry.."\"}")
elsengx.say("{\"c_type\":0,\"country_code\":\""..usercountry.."\"}")
end

访问:
http://common-info.chinasoft.com/api/v1/checkeu

返回:

{"c_type":0}
{"c_type":0,"country_code":"CN"}

转载于:https://www.cnblogs.com/reblue520/p/11459250.html

openresty开发系列40--nginx+lua实现获取客户端ip所在的国家信息相关推荐

  1. openresty开发系列38--通过Lua+Redis 实现动态封禁IP

    openresty开发系列38--通过Lua+Redis 实现动态封禁IP 一)需求背景为了封禁某些爬虫或者恶意用户对服务器的请求,我们需要建立一个动态的 IP 黑名单.对于黑名单之内的 IP ,拒绝 ...

  2. openresty开发系列24--openresty中lua的引入及使用

    openresty开发系列24--openresty中lua的引入及使用 openresty 引入 lua 一)openresty中nginx引入lua方式 1)xxx_by_lua   ---> ...

  3. 获取客户端IP地址定位城市信息

    获取客户端IP地址定位城市信息 1.首先获取客户端的IP地址 function getIPaddress(){ $IPaddress=''; if (isset($_SERVER)){ if (iss ...

  4. java 获取 客户端端口_Java获取客户端IP、端口等信息

    Java获取客户端IP.端口等信息.txt花前月下,不如花钱"日"下.叶子的离开,是因为风的追求还是树的不挽留?干掉熊猫,我就是国宝!别和我谈理想,戒了!Java获取客户端IP.端 ...

  5. JAVA中经过nginx反向代理获取客户端ip并获取相关坐标等信息

    关于搜狐新浪ip库查询接口的使用 直接输出访客ip及所在城市: <script src="http://pv.sohu.com/cityjson?ie=utf-8" > ...

  6. openresty开发系列28--openresty中操作mysql

    openresty开发系列28--openresty中操作mysql Mysql客户端    应用中最常使用的就是数据库了,尤其mysql数据库,那openresty lua如何操作mysql呢?   ...

  7. openresty开发系列37--nginx-lua-redis实现访问频率控制

    openresty开发系列37--nginx-lua-redis实现访问频率控制 一)需求背景 在高并发场景下为了防止某个访问ip访问的频率过高,有时候会需要控制用户的访问频次 在openresty中 ...

  8. openresty开发系列33--openresty执行流程之3重写rewrite和重定向

    openresty开发系列33--openresty执行流程之3重写rewrite和重定向 重写rewrite阶段 1)重定向 2)内部,伪静态 先介绍一下if,rewrite指令 一)if指令 语法 ...

  9. openresty开发系列33--openresty执行流程之2重写赋值阶段

    openresty开发系列33--openresty执行流程之2重写赋值阶段 一)重写赋值阶段 1)set_by_lua 语法:set_by_lua $res <lua-script-str&g ...

最新文章

  1. 我成功攻击了Tomcat服务器,大佬们的反应亮了
  2. C#通过继电器接收PD132地感设备信号
  3. 敲诈英伟达的竟然是一群未成年???
  4. 超级干货:你应该知道的那些编程原则!!
  5. 【linux】Linux配置环境变量
  6. Ubuntu 用户提权到Root
  7. 高性能极致用户体验前端开发实战
  8. Dijkstra最短路算法
  9. 我国研发出勒索病毒防御软件:能阻止其破坏文件
  10. python模拟按键_Python在windows下模拟按键和鼠标点击代码
  11. 关于Android的方向传感器
  12. 如何计算 R 中卡方统计量的 P 值
  13. OSChina 周六乱弹 —— 啊,谢谢好心的先生
  14. origin里绘制横纵坐标都不一致的两条曲线
  15. 数字IC后端物理实现流程1-环境建立
  16. 转:Spark案例:Scala版统计单词个数
  17. Python 经纬度,偏航角,距离计算
  18. maven打包war包
  19. matlab premnmx 逆函数,请帮我吧这些数据利用MATLAB premnmx语句进行归一化,高分跪求。...
  20. 简化开发|Lombok神器带你消除冗余代码

热门文章

  1. LeetCode精讲题 10正则表达式匹配(动态规划)
  2. CSDN登录机制分析(附上python、java代码)
  3. iOS - 数据持久化之 FMDB 的使用
  4. windows密钥连接linux,windows使用密钥登录linux
  5. 【教程】手把手企业FTP搭建实例
  6. Cilium 首次集成国内云服务,阿里云 ENI 被纳入新版本特性
  7. java mysql blob 存储图片,Java实现用Mysql存取图片操作实例
  8. 红盟php 解密,php教程_神盾加密解密教程(一)PHP变量可用字符
  9. php 有 stringbuffer,string,stringbuffer以及stringbuilder的区别
  10. rand生成随机数的范围_JS中生成指定范围随机数