作者:上海传安光通科技有限公司_839 | 来源:互联网 | 2017-11-06 09:43
1、判断手机用户
一般通过User-Agent来判断,从网上抄一抄,那些列出的都不错,我的配置里加上了Java、curl和Wget,方便调试和其它内部项目的抓取。
因为现在很多手机网关没有发送User-Agent,所以大部分手机发送的User-Agent到了网关就被过滤掉了,相当于是空值。经过抽样调查,User-Agent为空且为手机用户比例比较大。有部分User-Agent为空的是一些蜘蛛或垃圾程序的造访,这些垃圾流量并不那么重要。希望手机网关将来有相应的标准,不要发送空的User-Agent,就是发送一个字母也好啊。
如果应用有一个独立域名,也未必要做手机判断。譬如新浪有独立域名且深入人心,那它做不做跳转无关紧要。
nginx配置用穷举方式罗列各类手机User-Agent并把空User-Agent也转到手机应用里,非这些情况,则跳到帮助页面。
set $ismob 0;
if ( $http_user_agent ~ (MIDP)|(WAP)|(UP.Browser)|(Smartphone)|(Obigo)|(Mobile)|(AU.Browser)|(wxd.Mms)|(WxdB.Browser)|(CLDC)|(UP.Link)|(KM.Browser)|(UCWEB)|(SEMC-Browser)|(Mini)|(Symbian)|(Palm)|(Nokia)|(Panasonic)|(MOT-)|(SonyEricsson)|(NEC-)|(Alcatel)|(Ericsson)|(BENQ)|(BenQ)|(Amoisonic)|(Amoi-)|(Capitel)|(PHILIPS)|(SAMSUNG)|(Lenovo)|(Mitsu)|(Motorola)|(SHARP)|(WAPPER)|(LG-)|(LG/)|(EG900)|(CECT)|(Compal)|(kejian)|(Bird)|(BIRD)|(G900/V1.0)|(Arima)|(CTL)|(TDG)|(Daxian)|(DAXIAN)|(DBTEL)|(Eastcom)|(EASTCOM)|(PANTECH)|(Dopod)|(Haier)|(HAIER)|(KONKA)|(KEJIAN)|(LENOVO)|(Soutec)|(SOUTEC)|(SAGEM)|(SEC-)|(SED-)|(EMOL-)|(INNO55)|(ZTE)|(iPhone)|(Android)|(Windows CE)|(Wget)|(Java)|(curl)|(Opera) )
{
set $ismob 1;
proxy_pass http://m.sudone.com;
}
if ( $http_user_agent ~ ^$ )
{
set $ismob 1;
proxy_pass http://m.sudone.com;
}
if ( $ismob = 0 )
{
rewrite ^.*$ http://help.m.sudone.com/ permanent;
}
另一种配置方法:可以利用nginx的browser模块配置,参考:
http://sudone.com/nginx/nginx_browser_module.html
注意:使用上面的正则表达式的办法要求nginx版本为0.7.43或以下,0.7.44版到0.8版都会有问题。
2、Content-Type
手机浏览器和普通电脑访问页面有所不同,绝大多数手机不支持text/html这种Content-Type格式。在web服务方面,除了要做出合适手机浏览的页面,另外一个重要的事情就是要把Content-Type弄对了。一般手机使用的是text/vnd.wap.wml和application/xhtml+xml,听说text/vnd.wap.wml是老式手机专用,application/xhtml+xml是3g标准指定的Content-Type,另外charset需要指明为UTF-8。
所以Content-Type就应像如下:
Content-Type: application/xhtml+xml; charset=UTF-8
这样就对了。
对于动态页面,Content-Type可以在程序里设定。
譬如php:
header(Content-Type: application/xhtml+xml; charset=UTF-8)
jsp的话,把顶头的page改了就好。
<%@page cOntentType=application/xhtml+xml; charset=UTF-8%>
动态程序里的设定,到了nginx上默认会继承,所以不用太多考虑。nginx要做的一个是静态页面,另一个是302跳转。
静态页面的Content-Type改起来不麻烦,修改mime.types:
application/xhtml+xml html htm shtml;
application/xhtml+xml xml;
把需要的扩展名对应的类型改一改就好了。然后在nginx.conf里指定charset UTF-8;并加上charset_types text/vnd.wap.wml;和charset_types application/xhtml+xml;,charset_types这个指令在0.6版的nginx下是没有的,因此需要用0.7版,一般用的是0.7.43版。
麻烦的是301和302跳转,nginx中使用rewrite的redirect和permanent跳转的时候,Content-Type怎么改都会是text/html,使用add_header,Content-Type变成了两行,没能达成目的。用代理到动态程序固然行,但性能和稳定性又成了问题。最后查阅了nginx源码,发现这个text/html是写死的……
我调试的这个nginx是0.7.30版的,文件:
vi ./src/http/ngx_http_special_response.c
568 //r->headers_out.content_type_len = sizeof(text/html) - 1;
569 //r->headers_out.content_type.len = sizeof(text/html) - 1;
570 //r->headers_out.content_type.data = (u_char *) text/html;
把568 569 570这三行代码注释掉,就可以让nginx跳转时不发送Content-Type,我发现在电脑的IE/FF浏览器上没有Content-Type也能正常跳转。
当然,为了严谨一些,写上Content-Type吧,现在可以用add_header定义:
add_header Content-Type text/html;
手机的就是:
add_header Content-Type application/xhtml+xml;
3、缓存
如果前端不是nginx,而是squid缓存,页面或是跳转都有可能被缓存住,造成访问问题,这时需要利用Vary这个header。查看网页的response header一般都有Vary头(服务器支持压缩的都有),意思是说squid要把客户端传来的某个头区别对待,譬如Vary:Accept-Encoding,客户端发来Accept-Encoding:gzip(MSIE), deflate时squid会为gzip, deflate做一个存档;如果客户端没发来Accept-Encoding这个头(wget),squid又会为无Accept-Encoding做另一个存档;这两个存档的内容是不一样的,gzip, deflate的是压缩后的内容,一堆乱码,无Accept-Encoding的则是网页源码。
知道了Vary的原理,剩下的事就容易了,在网页输出时加上Vary:User-Agent,意味着squid要为每一种User-Agent存一个存档,nginx里这样配置即可:
add_header Vary User-Agent;
这时网页的response header会有两行Vary:
Vary:Accept-Encoding;
Vary:User-Agent;
这倒无伤大雅,能正常工作。
因为目前User-Agent被各种改装的浏览器改来改去,所以版本特多,这会在squid上造成很多的存档,穿透也会相应增加,所以要仔细监控。
4、内核配置
在nginx特别是做代理的机器上,通常系统管理员都会把这两个内核参数设为1:
/proc/sys/net/ipv4/tcp_tw_recycle(net.ipv4.tcp_tw_recycle)= 1
/proc/sys/net/ipv4/tcp_tw_reuse(net.ipv4.tcp_tw_reuse)= 1
但这个配置会导致手机用CMWAP访问时出问题,因此要将这两个参数设为0。