lizongbo at 618119.com 工作,生活,Android,前端,Linode,Ubuntu,nginx,java,apache,tomcat,Resin,mina,Hessian,XMPP,RPC

2011年08月21日

手机wap网站开发过程中通过dtd校验来检查wap1.0和wap2.0的页面语法

Filed under: Xhtml — 标签:, , , , , , , — lizongbo @ 13:40

手机wap网站开发过程中通过dtd校验来检查wap1.0和wap2.0的页面语法

对手机wap网站的wap1.0和wap2.0页面内容进行dtd的校验非常有价值,既可以保证页面对移动终端的兼容性,也能促使开发人员写出高质量的代码。

以前早期在做普通web页面开发的时候,对html的语法一知半解就开搞,标签不闭合,嵌套错误等问题从来没注意过,只管在IE6里打开能正常显示即可,
结果带来的后果就是在页面某个位置需要插入一段新内容时,整个页面就错位了,变得非常难看,也不知道怎么样来搞好,痛苦万分。

后来进行的是wap页面开发,wap页面用的是wap1.0的xml,加上各种山寨手机对wap页面的解析可不像电脑上的浏览器那样可以对错误的写法进行兼容,于是各种兼容性问题就出来了。
因此学会了用m3gate打开页面进行检查,只有m3gate打开时不出错的页面,才能放心的在各种山寨上正常显示而不出错。
再到后来,经过学习和总结,发现m3gate的检查其实和dtd校验的效果是一样的,于是摸索出通过dtd校验来发现标签嵌套错误等问题。

移动终端的发展是日新月异,很快就进入到了wap2.0时代,当然这个时候的手机浏览器对wap2.0的兼容性就好多了。
一些小的错误,也能兼容掉,但是难免也出现莫名其妙的错误,由于wap2.0的xml元素定义用的也还是dtd,因此继续用dtd校验来搞定。

wap1.0和wap2.0的自动化监控校验流程如下:
测试工具访问各个页面,获取对应的xml内容,保存为字符串,然后将页面的dtd声明部分,替换为对应的本地声明映射(这样避免联网获取dtd文件而影响性能),
生成新的字符串,然后使用java的xml parser进行解析,解析过程中如果有抛出各种异常,那就是把页面内容有错的地方全部揪出来了,再通知开发人员进行页面内容的bug修复。
通常比如img元素缺少alt属性等问题都可以及时发现。

正式环境则通过自动化监控脚本定期访问业务进行检查。

进行dtd校验的相关代码如下:

1.将远程的dtd等实体解析映射到本地的LocalEntityResolver(自动化监控中是通过字符串替换来将dtd的声明替换为本地路径,我是直接通过EntityResolver来进行映射):

[code]
package com.lizongbo.xml;

import java.io.IOException;

import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
* 将xml组件依赖的远程的schema文件都映射到本地
*
* @author lizongbo
*
*/
public class LocalEntityResolver implements EntityResolver {

@Override
public InputSource resolveEntity(String publicId, String systemId)
throws SAXException, IOException {
System.out.println(“publicId==” + publicId + “,systemId==” + systemId);
if (“-//W3C//DTD XHTML 1.0 Strict//EN”.equals(publicId)) {
String url = “/com/lizongbo/web/validation/dtds/www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd”;
System.out.println(systemId + ” LocalEntityResolver yyyy map to:”
+ url);
System.out.println(String.class.getResource(url));
if (String.class.getResource(url) != null) {
InputSource is = new InputSource(
String.class.getResourceAsStream(url));
is.setPublicId(publicId);
is.setSystemId(systemId);
return is;
}
}
if (systemId != null) {
String ids[] = new String[] { “/xhtml-attribs-1.mod”,
“/xhtml-notations-1.mod”, “/xhtml-datatypes-1.mod”,
“/xhtml-qname-1.mod”, “/xhtml-mobile10-model-1.mod”,
“/xhtml-mobile10-model-1.mod”, “xhtml-charent-1.mod”,
“/xhtml-symbol.ent”, “/xhtml-lat1.ent”,
“/xhtml-special.ent”, “/xhtml-inlstruct-1.mod”,
“/xhtml-inlphras-1.mod”, “/xhtml-blkstruct-1.mod”,
“xhtml-blkphras-1.mod”, “/xhtml-lat1.ent”,
“/xhtml-lat1.ent” };

for (int i = 0; i < ids.length; i++) {
if (systemId.endsWith(ids[i])) {
String url = “/com/lizongbo/web/validation/dtds/www.w3.org/xhtml-modularization/DTD/”
+ systemId.substring(systemId.lastIndexOf(“/”) + 1);
System.out.println(” local ” + systemId + ” try map to:”
+ url);
if (String.class.getResource(url) == null) {
url = “/com/lizongbo/web/validation/dtds/www.w3.org/TR/xhtml-modularization/DTD/”
+ systemId
.substring(systemId.lastIndexOf(“/”) + 1);
System.out.println(” local ” + systemId
+ ” retry map to:” + url);
}
if (String.class.getResource(url) == null) {
url = “/com/lizongbo/web/validation/dtds/www.wapforum.org/DTD/”
+ systemId
.substring(systemId.lastIndexOf(“/”) + 1);
System.out.println(” local ” + systemId
+ ” retry map to:” + url);
}
System.out.println(“try get ”
+ String.class.getResource(url));
if (String.class.getResource(url) != null) {
InputSource is = new InputSource(
String.class.getResourceAsStream(url));
is.setPublicId(publicId);
is.setSystemId(systemId);
return is;
}
}
}
if (systemId.endsWith(“.xsd”)) {
String url = “/com/lizongbo/web/validation/xsds/”
+ systemId.replace(“http://”, “”);
System.out.println(systemId + ” LocalEntityResolver 22 map to:”
+ url);
System.out.println(String.class.getResource(url));
if (String.class.getResource(url) != null) {
InputSource is = new InputSource(
String.class.getResourceAsStream(url));
is.setPublicId(publicId);
is.setSystemId(systemId);
return is;
}
} else {
String url = “/com/lizongbo/web/validation/dtds/”
+ systemId.replace(“http://”, “”);
System.out.println(systemId + ” LocalEntityResolver 11 map to:”
+ url);
System.out.println(String.class.getResource(url));
if (String.class.getResource(url) == null) {
url = “/com/lizongbo/web/validation/dtds/www.w3.org/TR/xhtml-modularization/DTD/”
+ systemId.replace(“http://”, “”);
System.out.println(” local ” + systemId + ” retry map to:”
+ url);
}
if (String.class.getResource(url) != null) {
InputSource is = new InputSource(
String.class.getResourceAsStream(url));
is.setPublicId(publicId);
is.setSystemId(systemId);
return is;
}
}
}
return null;
}
}

[/code]

2.实际校验的代码:
[code]
package com.lizongbo.xml;

import java.io.*;
import java.net.*;

import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.xml.parsers.*;

/**
* DTD校验工具类
*
* @author lizongbo
*
*/
public class DTDUtil {

/**
* @param args
* @throws SAXException
* @throws ParserConfigurationException
*/
public static void main(String[] args) throws SAXException,
ParserConfigurationException {
String urls[] = new String[] { “http://3g.sina.com.cn/?vt=1&pos=200”,// 新浪wap1.0
http://3g.sina.com.cn/?vt=3&pos=200”,// 新浪wap2.0
http://wap.sohu.com/?nid=1&v=1”,// 搜狐 wap1.0
http://wap.sohu.com/?nid=1&v=3”,// 搜狐 wap2.0
http://info50.3g.qq.com/g/s?aid=index&g_ut=1”,// 手机腾讯网wap1.0
http://info50.3g.qq.com/g/s?aid=index&g_ut=2”, // 手机腾讯网wap2.0
};
for (int i = 0; i < urls.length; i++) {
try {
String urlStr = urls[i];
String xml = downloadUrl(urlStr, null, “UTF-8”);
// System.out.println(xml);
validateWap(xml);
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println(“Over”);
}

/**
* 通过dtd校验wap2.0页面内容,如果抛出异常则说明页面内容有错
*
* @param xml
* @throws ParserConfigurationException
* @throws SAXException
* @throws IOException
*/
public static void validateWap(String xml)
throws ParserConfigurationException, SAXException, IOException {
// //xml = setDTDforWap20(xml);
// //System.out.println(xml);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setValidating(true);
DocumentBuilder db = dbf.newDocumentBuilder();
db.setEntityResolver(new LocalEntityResolver());
Document doc = db.parse(new InputSource(new StringReader(xml)));
System.out.println(doc.getFirstChild());
}

public static String downloadUrl(String urlStr, String referer,
String encoding) throws Exception {
String line = “”;
StringBuilder sb = new StringBuilder();
HttpURLConnection httpConn = null;
try {
URL url = new URL(urlStr);
System.out.println(urlStr);
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(
“proxy.lizongbo.com”, 8080));
proxy = Proxy.NO_PROXY;
httpConn = (HttpURLConnection) url.openConnection(proxy);
httpConn.setRequestProperty(“User-Agent”, “Nokia”);
httpConn.setDoInput(true);
httpConn.setDoOutput(true);
httpConn.setRequestMethod(“GET”);
if (referer != null) {
httpConn.setRequestProperty(“Referer”, referer);
}
httpConn.setConnectTimeout(1000);
BufferedReader in = null;
if (httpConn.getResponseCode() != 200) {
System.err.println(“error:” + httpConn.getResponseMessage());
in = new BufferedReader(new InputStreamReader(
httpConn.getErrorStream(), “UTF-8”));
} else {
in = new BufferedReader(new InputStreamReader(
httpConn.getInputStream(), “UTF-8”));
}
while ((line = in.readLine()) != null) {
sb.append(line).append(‘\n’);
}
System.out.println(httpConn.getHeaderFields());
// 关闭连接
httpConn.disconnect();
return sb.toString();
} catch (Exception e) {
// 关闭连接
if (httpConn != null) {
try {
httpConn.disconnect();
} catch (Exception e2) {
// TODO: handle exception
}
}
System.out.println(e.getMessage());
throw e;
}
}
}

[/code]

通过上面的例子,可以看到新浪,搜狐,手机腾讯网的wap1.0都校验ok。
而新浪的wap2.0(3G版)使用的声明不是http://www.wapforum.org/DTD/xhtml-mobile10.dtd,却是:xhtml1-strict.dtd

按xhtml1-strict.DTD校验的出错信息为:
Error: URI=null Line=127: Attribute “width” must be declared for element type “input”.
Error: URI=null Line=127: Attribute “height” must be declared for element type “input”.
Error: URI=null Line=127: The content of element type “form” must match “(p|h1|h2|h3|h4|h5|h6|div|ul|ol|dl|pre|hr|blockquote|address|fieldset|table|noscript|ins|del|script)*”.
Error: URI=null Line=155: The content of element type “form” must match “(p|h1|h2|h3|h4|h5|h6|div|ul|ol|dl|pre|hr|blockquote|address|fieldset|table|noscript|ins|del|script)*”.
Error: URI=null Line=236: Attribute value “gototop” of type ID must be unique within the document.
搜狐的wap2.0(彩版)虽然使用的dtd声明是:http://www.wapforum.org/DTD/xhtml-mobile10.dtd,但是页面内容中却使用xhtml1所定义的元素。
按xhtml-mobile10.dtd校验的出错信息为:
Error: URI=null Line=63: Element type “script” must be declared.
Error: URI=null Line=99: The content of element type “div” must match “(h1|h2|h3|h4|h5|h6|ul|ol|dl|p|div|pre|blockquote|address|hr|table|form|fieldset|br|span|em|strong|dfn|code|samp|kbd|var|cite|abbr|acronym|q|i|b|big|small|a|img|object|input|select|textarea|label)”.
Error: URI=null Line=100: Attribute “name” must be declared for element type “form”.
Error: URI=null Line=100: Attribute “accept-charset” must be declared for element type “form”.
Error: URI=null Line=107: Attribute “onclick” must be declared for element type “a”.
Error: URI=null Line=108: Attribute “onclick” must be declared for element type “a”.
Error: URI=null Line=109: Attribute “onclick” must be declared for element type “a”.
Error: URI=null Line=110: The content of element type “form” must match “(h1|h2|h3|h4|h5|h6|ul|ol|dl|p|div|pre|blockquote|address|hr|table|fieldset)+”.
Error: URI=null Line=112: Element type “font” must be declared.
Error: URI=null Line=112: The content of element type “div” must match “(h1|h2|h3|h4|h5|h6|ul|ol|dl|p|div|pre|blockquote|address|hr|table|form|fieldset|br|span|em|strong|dfn|code|samp|kbd|var|cite|abbr|acronym|q|i|b|big|small|a|img|object|input|select|textarea|label)”.

手机腾讯网的wap2.0使用xhtml-mobile10.dtd进行校验,出错信息最少,只有一条:
Error: URI=null Line=141: The content of element type “form” must match “(h1|h2|h3|h4|h5|h6|ul|ol|dl|p|div|pre|blockquote|address|hr|table|fieldset)+”.

 

 

2011年01月26日

web网站判断是手机访问还是pc电脑访问的检测逻辑

Filed under: Android,前端开发 — 标签:, , , , , , — lizongbo @ 00:25

web网站判断是手机访问还是pc电脑访问的检测逻辑

在现在手机上网和wifi越来越普及的情况下,web网站需要对http的客户端进行区分并适配不同的页面,确保给用户最合适的体验效果。
因此从网站服务器端去分析,区分当前http请求是来自mobile的手机上的浏览器,还是来自Windows,Linux,Mac等PC电脑上的浏览器,就显得非常有必要了。
根据相关日志分析后总结出简单的识别逻辑规则如下:
首先从上网方式上来区分手机终端行为:用手机上网可能通过cmwap方式,cmnet方式,3g网络,wifi方式等
除了cmwap方式,其它方式上网的网络情况除了网速区别,其它情况基本一样。
因为存在有人在电脑上通过3g卡等方式上网,因此识别逻辑必须先识别明确就是电脑上的浏览器的ua,当作来自电脑的请求。
然后再识别cmwap网关的特征,包含特征的,则认为该请求来自手机终端。
其次再做手机ua识别,属于手机ua特征的,再当作手机请求,其它均当作电脑pc端的请求访问。
(不考虑用Accept这个header进行识别,因为这个头信息有很多是乱填的,完全不靠谱。)

通过对http头信息的分析检测,这样可以当前请求进行适配展现最适合的页面内容,让pc用户看web页面,手机用户看wap页面。

[code]
package com.lizongbo.web.common;

import javax.servlet.http.HttpServletRequest;

public class HttpReqUtil {
/**Wap网关特有和某些手机终端浏览器特有的头信息*/
private static String mobileHeaders[]=new String[]{
“HTTP_X_UP_CALLING_LINE_ID”,//cmwap情况下中国移动的手机号码,目前基本没有这个head了
“x-up-calling-line-id”,//uniwap情况下下中国联通手机号码,例如:x-up-calling-line-id=8615***618119,某些移动网关也用这个header放手机号码
“x-wap-profile”,//手机终端才会有的uaprof文件url,例如:x-wap-profile=”http://nds1.nds.nokia.com/uaprof/Nokia5800d-1r100-2G.xml
“X_WAP_PROFILE”,//X_WAP_PROFILE=http://nds1.nds.nokia.com/uaprof/N6670r100.xml
“X-Nokia-MusicShop-Bearer”,//诺基亚手机送来的网络类型,例如X-Nokia-MusicShop-Bearer=GPRS/3G
“X-Nokia-MusicShop-Version”,//诺基亚网关送的参数,例如:X-Nokia-MusicShop-Version=11.1014.15
“x-up-bear-type”,//wap网关的参数,疑似上网类型,例如:x-up-bear-type=GPRS,或x-up-bear- type=GPRS/EDGE,X-Up-Bearer-Type=CSD,x-up-bear-type=CDMA CSD,x-up-bear-type=TD-SCDMA
“X-Nokia-BEARER”,//诺基亚wap网关的参数,疑似上网类型,例如:X-Nokia-BEARER=WCDMA,或X-Nokia-BEARER=GPRS
“X-Nokia-Gateway-Id”,//诺基亚wap网关的参数,例如:X-Nokia-Gateway-Id=NBG/3.0/1,或X-Nokia-gateway-id=NWG/4.1/Build4.1.04
“X-Nokia-MSISDN”,//诺基亚wap网关的参数,疑似用户手机号码,例如X-Nokia-MSISDN=861860*******
“x-source-id”,//cmwap网关参数,例如:x-source-id=220.206.156.33,也有:X-Source-ID=FZGGSN31
“X-Nokia-CONNECTION_MODE”,//wap网关参数,例如:X-Nokia-CONNECTION_MODE=TCP
“X-Nokia-MaxDownlinkBitrate”,//诺基亚wap网关参数,含义未知,例如:X-Nokia-MaxDownlinkBitrate=0
“X-Nokia-MaxUplinkBitrate”,//诺基亚wap网关参数,含义未知,例如:X-Nokia-MaxUplinkBitrate=0
“Bearer-Indication”,//不明参数,例如:Bearer-Indication=11,    Bearer-Indication=gsm_gprs_ipv4
“X_NETWORK_INFO”,//X_NETWORK_INFO=GPRS,86136********,10.100.246.217,cmwap,unsecured
“x-NAS-Identifier”,//含义不明,例如:x-NAS-Identifier=fj-telecom-cdma-pdsn
“x-online-host”,//cmwap客户端向cmwap指定header,不知道怎么的移动把它送给服务器了,例如:x-online-host=b.wap.618119.com:80
“X_WAP_CLIENTID”,//疑似加密处理后的用户身份信息,例如X_WAP_CLIENTID=618119**********
//以下是OperaMini特有的header ,see: http://dev.opera.com/articles/view/opera-mini-request-headers/
“X-OperaMini-Features”,//OperaMini特有的客户端特性描述。例如:X-OperaMini- Features=advanced, download, file_system,X-OperaMini-Features=advanced, file_system, camera, touch, folding
“X-OperaMini-Phone-UA”,//OperaMini特有的传原始UserAgent的header。例如:X-OperaMini- Phone-UA=BlackBerry8310/4.5.0.174 Profile/MIDP-2.0 Configuration/CLDC-1.1 VendorID/107,此时的User-Agent=Opera/9.80 (BlackBerry; Opera Mini/5.1.22555/20.2485; U; zh) Presto/2.5.25
“X-OperaMini-Phone”,//OperaMini特有的自己提取的机型信息,品牌和型号直接用井号隔开,信息不靠谱,例如:X-OperaMini-Phone=BlackBerry # BlackBerry 8310
“X-OperaMini-UA”,//OperaMini特有的ua描述信息,例如:X-OperaMini-UA=Opera Mini/5.1.22555/hifi/om511china/zh
};
/**Wap网关Via头信息中特有的描述信息*/
private static String mobileGateWayHeaders[]=new String[]{
“ZXWAP”,//中兴提供的wap网关的via信息,例如:Via=ZXWAP GateWay,ZTE Technologies,
“chinamobile.com”,//中国移动的诺基亚wap网关,例如:Via=WTP/1.1 GDSZ-PB-GW003-WAP07.gd.chinamobile.com (Nokia WAP Gateway 4.1 CD1/ECD13_D/4.1.04)
“monternet.com”,//移动梦网的网关,例如:Via=WTP/1.1 BJBJ-PS-WAP1-GW08.bj1.monternet.com. (Nokia WAP Gateway 4.1 CD1/ECD13_E/4.1.05)
“infoX”,//华为提供的wap网关,例如:Via=HTTP/1.1 GDGZ-PS-GW011-WAP2 (infoX-WISG, Huawei Technologies),或Via=infoX WAP Gateway V300R001, Huawei Technologies
“XMS 724Solutions HTG”,//国外电信运营商的wap网关,不知道是哪一家
“wap.lizongbo.com”,//自己测试时模拟的头信息
“Bytemobile”,//貌似是一个给移动互联网提供解决方案提高网络运行效率的,例如:Via=1.1 Bytemobile OSN WebProxy/5.1
};
/**电脑上的IE或Firefox浏览器等的User-Agent关键词*/
private static String pcHeaders[]=new String[]{
“Windows 98”,
“Windows ME”,
“Windows 2000”,
“Windows XP”,
“Windows NT”,
“Ubuntu”,
};
/**手机浏览器的User-Agent里的关键词*/
private static String mobileUserAgents[]=new String[]{
“Nokia”,//诺基亚,有山寨机也写这个的,总还算是手机,Mozilla/5.0 (Nokia5800 XpressMusic)UC AppleWebkit(like Gecko) Safari/530
“SAMSUNG”,//三星手机 SAMSUNG-GT-B7722/1.0+SHP/VPP/R5+Dolfin/1.5+Nextreaming+SMM-MMS/1.2.0+profile/MIDP-2.1+configuration/CLDC-1.1
“MIDP-2”,//j2me2.0,Mozilla/5.0 (SymbianOS/9.3; U; Series60/3.2 NokiaE75-1 /110.48.125 Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/413 (KHTML, like Gecko) Safari/413
“CLDC1.1”,//M600/MIDP2.0/CLDC1.1/Screen-240X320
“SymbianOS”,//塞班系统的,
“MAUI”,//MTK山寨机默认ua
“UNTRUSTED/1.0”,//疑似山寨机的ua,基本可以确定还是手机
“Windows CE”,//Windows CE,Mozilla/4.0 (compatible; MSIE 6.0; Windows CE; IEMobile 7.11)
“iPhone”,//iPhone是否也转wap?不管它,先区分出来再说。Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_1 like Mac OS X; zh-cn) AppleWebKit/532.9 (KHTML, like Gecko) Mobile/8B117
“iPad”,//iPad的ua,Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; zh-cn) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B367 Safari/531.21.10
“Android”,//Android是否也转wap?Mozilla/5.0 (Linux; U; Android 2.1-update1; zh-cn; XT800 Build/TITA_M2_16.22.7) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17
“BlackBerry”,//BlackBerry8310/2.7.0.106-4.5.0.182
“UCWEB”,//ucweb是否只给wap页面? Nokia5800 XpressMusic/UCWEB7.5.0.66/50/999
“ucweb”,//小写的ucweb,貌似是uc的代理服务器,Mozilla/6.0 (compatible; MSIE 6.0;) Opera ucweb-squid
“BREW”,//很奇怪的ua,例如:REW-Applet/0x20068888 (BREW/3.1.5.20; DeviceId: 40105; Lang: zhcn) ucweb-squid
“J2ME”,//,很奇怪的ua,只有J2ME四个字母
“YULONG”,//宇龙手机,YULONG-CoolpadN68/10.14 IPANEL/2.0 CTC/1.0
“YuLong”,//还是宇龙
“COOLPAD”,//宇龙酷派,YL-COOLPADS100/08.10.S100 POLARIS/2.9 CTC/1.0
“TIANYU”,//天语手机,TIANYU-KTOUCH/V209/MIDP2.0/CLDC1.1/Screen-240X320
“TY-“,//天语,TY-F6229/701116_6215_V0230 JUPITOR/2.2 CTC/1.0
“K-Touch”,//还是天语,K-Touch_N2200_CMCC/TBG110022_1223_V0801 MTK/6223 Release/30.07.2008 Browser/WAP2.0
“Haier”,//海尔手机,Haier-HG-M217_CMCC/3.0 Release/12.1.2007 Browser/WAP2.0
“DOPOD”,//多普达手机,
“Lenovo”,//联想手机,Lenovo-P650WG/S100 LMP/LML Release/2010.02.22 Profile/MIDP2.0 Configuration/CLDC1.1
“LENOVO”,//联想手机,比如:LENOVO-P780/176A
“HUAQIN”,//华勤手机
“AIGO-“,//爱国者居然也出过手机,AIGO-800C/2.04 TMSS-BROWSER/1.0.0 CTC/1.0
“CTC/1.0”,//含义不明
“CTC/2.0”,//含义不明
“CMCC”,//移动定制手机,K-Touch_N2200_CMCC/TBG110022_1223_V0801 MTK/6223 Release/30.07.2008 Browser/WAP2.0
“DAXIAN”,//大显手机,DAXIAN X180 UP.Browser/6.2.3.2(GUI) MMP/2.0
“MOT-“,//摩托罗拉,MOT-MOTOROKRE6/1.0 LinuxOS/2.4.20 Release/8.4.2006 Browser/Opera8.00 Profile/MIDP2.0 Configuration/CLDC1.1 Software/R533_G_11.10.54R
“SonyEricsson”,//索爱手机,SonyEricssonP990i/R100 Mozilla/4.0 (compatible; MSIE 6.0; Symbian OS; 405) Opera 8.65 [zh-CN]
“GIONEE”,//金立手机
“HTC”,//HTC手机
“ZTE”,//中兴手机,ZTE-A211/P109A2V1.0.0/WAP2.0 Profile
“HUAWEI”,//华为手机,
“webOS”,//palm手机,Mozilla/5.0 (webOS/1.4.5; U; zh-CN) AppleWebKit/532.2 (KHTML, like Gecko) Version/1.0 Safari/532.2 Pre/1.0
“GoBrowser”,//3g GoBrowser.User-Agent=Nokia5230/GoBrowser/2.0.290 Safari
“IEMobile”,//Windows CE手机自带浏览器,
“WAP2.0”,//支持wap 2.0的
};
/**
* 根据当前请求的特征,判断该请求是否来自手机终端,主要检测特殊的头信息,以及user-Agent这个header
* @param request http请求
* @return 如果命中手机特征规则,则返回对应的特征字符串
*/
public static boolean isFromMobile(HttpServletRequest request) {// 识别当前请求,针对来自手机的请求则跳转到wap页面。
return getFromMobileRule(request)!=null;
}
public static String  getFromMobileRule(HttpServletRequest request) {
String userAgent = request.getHeader(“User-Agent”);
if (userAgent != null) {
for (String mheader : pcHeaders) {
if (userAgent.contains(mheader)) {
return null;
}
}
}

for (String mheader : mobileHeaders) {// 只要存在网关特有的header,肯定是手机
if (request.getHeader(mheader) != null
&& request.getHeader(mheader).length() > 0) {
return mheader;
}
}
String via = request.getHeader(“Via”);
if (via != null) {
for (String mheader : mobileGateWayHeaders) {
// 是不是wap网关的描述
if (via.contains(mheader)) {
return mheader;
}
}

}
if (userAgent != null) {
for (String mheader : mobileUserAgents) {
if (userAgent.contains(mheader)) {
return mheader;
}
}
}
return null;
}
}

[/code]

实际调用代码:

String mrule = HttpReqUtil.getFromMobileRule(request);
if (mrule != null && !mrule.equals(“iPhone”) && !mrule.equals(“iPad”)) {
//Android也都当作手机端,暂时不考虑pad
}

下面是某一段时间内命中相关检测规则的统计结果(前面是数量,后面的特征字符串):

1 CMCC
1 GoBrowser
1 Haier
1 K-Touch
1 MOT-
1 TY-
1 webOS
2 x-up-bear-type
3 CTC/2.0
3 HTC
4 COOLPAD
4 GIONEE
5 BlackBerry
7 Lenovo
8 X-Nokia-MusicShop-Bearer
12 ZTE
20 SymbianOS
27 CTC/1.0
36 CLDC1.1
45 SonyEricsson
162 J2ME
182 MAUI
231 SAMSUNG
288 ucweb
317 UNTRUSTED/1.0
489 MIDP-2
490 Windows CE
709 Android
1046 UCWEB
1170 x-wap-profile
1656 x-up-calling-line-id
3436 Nokia

Powered by WordPress