如何检测ASP中的浏览器。NET与浏览器文件

时间:2023-03-09 00:51:32
如何检测ASP中的浏览器。NET与浏览器文件

介绍 ASP。NET是一个用于使用Web表单、MVC、Web API和SignalR(这是官方定义)构建Web应用程序的高生产力框架。它是在。net框架上开发RESTful应用程序或使用HTML、CSS和javascript构建优秀Web站点和Web应用程序的理想平台。 但是,如果浏览器检测是您业务的主要关注点,您当然会注意到ASP。NET无法正确地执行这样的任务:我们将在本文的第一部分中深入说明这一点。然后,我们将在第二部分中看到如何通过修改浏览器文件的默认配置来优雅地绕过这个问题。 ASP.NET是什么? ASP。NET是一个免费的web框架,用于使用HTML、CSS和JavaScript构建网站和web应用程序。它还使我们能够通过SignalR创建Web api、移动站点和使用实时技术。它是由微软开发和维护的。 我们将在本文的其余部分开发一个ASP。NET Web API应用程序,但以下内容可以应用于所有其他的ASP组件,而不会丧失通用性。网络平台。ASP。NET Web api只是微软为提供HTTP上的数据服务而开发的解决方案。它简化了像内容协商这样的管道代码,并利用了HTML的强大功能。ASP。NET Web API在富客户端Web应用程序(无论是Silverlight应用程序还是任何像AngularJS这样的单页应用程序)或需要后端的移动应用程序方面特别出众。它也非常适合作为物联网平台。 注意一些缺点 ASP。NET功能强大,可以轻而易举地构建优秀的Web应用程序。尽管如此,它也有一个缺点,您必须意识到:浏览器检测不是它的强项。 我们将通过开发一个简单的应用程序来说明这一点,该应用程序旨在构建一个非常简化的web分析服务,类似于谷歌analytics。我们将收集客户端使用的浏览器,这个简短的例子将强调ASP的默认配置。用于浏览器检测的NET无法提供正确的结果。 设置我们的示例ASP。NET Web API应用程序 在本文中,我们使用Visual Studio 2013框架4.5.1。这个示例的灵感来自于asp.net中的教程。网络站点(这里)。 服务器端安装 启动Visual Studio 2013,并从“开始”页面选择“新项目”。在“模板”窗格中,选择“已安装的模板”并展开可视化c#  节点。Under  Visual c#, select 网络。在项目模板列表中,选择ASP。净的Web应用程序。,新的ASP。NET项目对话框,选择空模板。在“添加文件夹和核心引用”下,选中Web API。Click 好吧。在“解决方案资源管理器”中,右键单击Controllers文件夹。Select  Add 然后Select 控制器。在“添加脚手架”对话框中,选择“Web API控制器”为空。Click 添加。保持默认的控制器名称(DefaultController)。 客户端安装 现在我们添加一个使用AJAX调用web API的HTML页面。我们将使用jQuery进行AJAX调用。 在“添加新项目”对话框中,选择visualc#下的web节点,然后选择HTML页面项。将页面命名为“index.html”。将此文件中的所有内容替换为以下内容: 隐藏,Code<复印件;!DOCTYPE html> & lt; html xmlns = " http://www.w3.org/1999/xhtml "比; & lt; head> ,& lt; title> Example< / title> & lt; / head> & lt; body> ,& lt; div> ,,& lt; h2> Lorem ipsum…& lt; / h2>,,, ,& lt; / div> ,& lt;脚本src = " http://ajax.aspnetcdn.com/ajax/jQuery/jquery-2.0.3.min.js "祝辞& lt; / script> ,& lt; script> ,,var uri = 'api/default'; ,,美元(文档)。准备好(函数(){ ,,,,//发送AJAX请求。 ,,,,美元.getJSON (uri)。done(function (data) {}); ,,});,,, ,& lt; / script> & lt; / body> & lt; / html> 单击F5运行解决方案并检查是否一切正常。 检测使用ASP的浏览器。网络应用程序 一旦安装和配置,ASP。NET Web API使我们能够轻松地访问传入请求的一些基本属性:浏览器、平台等等。下面的代码举例说明了如何查找客户机使用的浏览器(将其添加到DefaultController类中)。 隐藏,复制Code

public IHttpActionResult Get()
{
HttpRequestBase baseRequest = ((HttpContextWrapper)Request.Properties["MS_HttpContext"]).Request as HttpRequestBase; HttpBrowserCapabilitiesBase browser = baseRequest.Browser; string b = browser.Browser + " " + browser.Version; // Here we can store the browser used in a data store (SqlServer, etc...). return Ok();
}

我们在这里确定浏览器名称和相关版本。 现在,让我们看看通过一些常见的浏览器可以获得什么。 当我使用Chrome浏览器时 浏览器被正确推断。 , 当我使用火狐浏览器时 好的,一切都很好。 , 当我使用Safari浏览器时 完美的。 , 当我使用Internet Explorer时 到目前为止,一切都好…… , 当我使用边缘 (Edge是微软(Microsoft)开发的网络浏览器,包含在该公司的Windows 10操作系统中,取代了ie浏览器。) 哼,哼。Edge被识别为Chrome(版本不正确)。啊。 , 这还没有结束。现在让我们看看通过一些罕见的浏览器可以获得什么。 当我使用Opera时 Opera被认为是Chrome。 , 当我使用丝绸(亚马逊) (丝绸主要分布在Kindle Fire上) Silk被认为是Safari(有一个奇怪的版本)。 , 当我用遨游游的时候 (傲游是中国开发的免费浏览器。) , 当我使用SeaMonkey的时候 (SeaMonkey与Firefox基于相同的源代码。) SeaMonkey更奇怪,我们得到了Mozilla 0.0。 , 我们可以用其他浏览器来举例。 因此我们可以看到,如果你想很好地检测浏览器,ASP。NET默认配置是不合适的,因为它只能推断出最常见的配置(甚至不能很好地检测到Edge)。毕竟,对于基本用法来说,它已经足够了,但是如果您的目标是更准确地限定用户,那么这个问题就必须解决。 但是为什么ASP。NET不能正确地检测这些浏览器? , ASP.NET是如何推断浏览器的 输入用户代理 每次你的浏览器连接到一个网站时,它都会发送一个字符串(即一行文本)来识别该网站及其运行的操作系统。这个字符串称为用户代理。下面是针对不同浏览器(基于不同的操作系统)的典型用户代理示例。 Chrome 47 Mozilla/5.0 (windowsnt 10.0;AppleWebKit/537.36 (KHTML,像Gecko) Chrome/47.0.2526.106 Safari/537.36 Firefox 43 Mozilla/5.0 (windowsnt 10.0;WOW64;房车:Firefox 40.0)壁虎/ 20100101 / 43.0 Safari 8 Mozilla / 5.0 (iPhone;CPU iPhone OS 8_4_1像Mac OS X) AppleWebKit/600.1.4 (KHTML,像Gecko)版本/8.0 Mobile/12H321 Safari/600.1.4 即11 Mozilla/5.0 (windowsnt 10.0;WOW64;三叉戟/ 7.0;房车:11.0)像壁虎一样 边缘 Mozilla/5.0 (windowsnt 10.0;Win64;x64) AppleWebKit/537.36 (KHTML,像Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10240 歌剧 Opera/9.80 (Windows NT 6.0) Presto/2.12.388版本/12.14 Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML,像Gecko) Chrome/47.0.2526.73 Safari/537.36 OPR/34.0.2036.25 丝2 Mozilla / 5.0 (Linux;U;en - us;KFTT Build/IML74K) AppleWebKit/535.19 (KHTML,像Gecko) Silk/2.1 Safari/535.19 Silk- accelerated =true 傲游浏览器4 Mozilla/5.0 (windowsnt 10.0;Maxthon/4.4.1.5000 Chrome/30.0.1599.101 Safari/537.36 (KHTML,像Gecko SeaMonkey 8 Mozilla / 5.0(窗口;U;Windows NT 10.0;WOW64;rv:1.8.0.7) Gecko/20110321 MultiZilla/4.33.2.6a SeaMonkey/8.6.55 描述用户代理的详尽结构超出了本文的范围。但是你已经可以看到Chrome 47包含了Safari,或者边缘包含了Chrome和Safari。所以,检测浏览器并不像在Chrome 47的用户代理中找到字符串Chrome或者在Edge中找到字符串Edge那么简单。 用户代理字段的内容因浏览器和操作系统的不同而不同。每个浏览器都有自己独特的用户代理。最终,用户代理是浏览器向web服务器说Hi的一种方式,在Windows上我是Firefox,在iPhone上我是Safari。 这就是ASP的这个用户代理。NET用来查找浏览器。让我们看看这是如何执行的。 好的,具体来说? 这在理论上看起来很简单,但实际上要复杂一点。因为随着时间的推移,用户代理已经变得一团糟,而且在不同的浏览器和操作系统之间都有很大的不同。NET使用复杂(但强大)的机制来检测浏览器。 我们在上面列出了一些用户代理的例子。从这个列表中,我们可以开始用命令式的伪代码编写浏览器检测: 查找用户代理是否包含字符串Opera。如果是,终止,浏览器是Opera。查找用户代理是否包含字符串Trident。如果是,终止,浏览器是IE。查找用户代理是否包含字符串Firefox。如果是,终止,浏览器是Firefox。查找用户代理是否包含字符串SeaMonkey。如果是,终止,浏览器是SeaMonkey。查找用户代理是否包含字符串Safari。如果是,终止,浏览器是Safari。查找用户代理是否包含字符串丝。如果是,终止,浏览器是Silk。查找用户代理是否包含字符串边。如果是,终止,浏览器是Edge。否则,浏览器就是Chrome。 由于图片通常比文字更能说明问题,下面的图表可能更清楚。 您可以看到,这段代码相当麻烦,也相当不优雅。如果我们必须添加一个新浏览器或一个新规则呢?如果浏览器改变了它的用户代理会怎样?ASP。NET提供了浏览器文件。浏览器文件是一种检测浏览器的方法,但是与前面提到的代码不同,它们用一种更自然的方式定义了层次结构。你可以在MSDN(这里)找到更多关于浏览器文件的细节。 但是浏览器文件是如何组织和构造的呢? 从上面的清单中可以看出,不同浏览器的用户代理有很大的不同,但它们仍然遵循一定的合理性。例如: 几乎每个人都以字符串Mozilla开头(Opera是个例外)。Firefox和IE不包含字符串AppleWebKit,与其他浏览器相反。… 我们可以从这些注释和在用户代理的层次结构之上开发的伪代码(见下文)中派生出来。 , 以下是如何阅读和使用这棵树: 从根(默认节点)开始 如果(用户代理包含Opera)返回Opera; else if(用户代理包含Mozilla)则 ,,,,,,,,,,,,,,如果(用户代理包含AppleWebKit)则 ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,如果(用户代理包含Chrome)返回Chrome; ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,else if(用户代理包含Safari)返回Safari; ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,否则返回WebKit; ,,,,,,,,,,,,,,else if(用户代理包含Firefox)返回Firefox; ,,,,,,,,,,,,,,else if(用户代理包含Trident)返回IE; ,,,,,,,,,,,,,,其他返回Mozilla; 否则返回未知; 浏览器文件只是尽可能模仿这种层次结构的XML文件。因此: 我们将有一个XML文件,它将模仿上一幅图的默认行为。我们将有一个XML文件,它将模仿上一幅图的Opera行为。等等…… ASP。模块“c”模块“windows7”中的Windows\Microsoft.NET\Framework64\v4.0.30319\Config\ browser”文件夹中包含默认的浏览器文件(见下文)。这些浏览器文件给出了它们在实践中的概况。 如果你打开其中一个文件(chrome。),您将发现以下内容。 隐藏,收缩,复制Code

<browsers>
<browserid="Chrome"parentID="WebKit">
<identification>
<userAgentmatch="Chrome/(?'version'(?'major'\d+)(\.(?'minor'\d+)?)\w*)"/>
</identification> <capabilities>
<capabilityname="browser"value="Chrome"/>
<capabilityname="majorversion"value="${major}"/>
<capabilityname="minorversion"value="${minor}"/>
<capabilityname="type"value="Chrome${major}"/>
<capabilityname="version"value="${version}"/>
<capabilityname="ecmascriptversion"value="3.0"/>
<capabilityname="javascript"value="true"/>
<capabilityname="javascriptversion"value="1.7"/>
<capabilityname="w3cdomversion"value="1.0"/>
<capabilityname="supportsAccesskeyAttribute"value="true"/>
<capabilityname="tagwriter"value="System.Web.UI.HtmlTextWriter"/>
<capabilityname="cookies"value="true"/>
<capabilityname="frames"value="true"/>
<capabilityname="javaapplets"value="true"/>
<capabilityname="supportsCallback"value="true"/>
<capabilityname="supportsDivNoWrap"value="false"/>
<capabilityname="supportsFileUpload"value="true"/>
<capabilityname="supportsMaintainScrollPositionOnPostback"value="true"/>
<capabilityname="supportsMultilineTextBoxDisplay"value="true"/>
<capabilityname="supportsXmlHttp"value="true"/>
<capabilityname="tables"value="true"/>
</capabilities>
</browser>
</browsers>

我们可以看到有一个填充了WebKit的parentID标签。这个标签指的是下面显示的另一个浏览器文件(generic.browser),它是chrome的父文件。文件浏览器。 隐藏,复制Code

<browserid="WebKit"parentID="Mozilla">
<identification>
<userAgentmatch="AppleWebKit"/>
</identification> <capture>
<userAgentmatch="AppleWebKit/(?'layoutVersion'\d+)"/>
</capture> <capabilities>
<capabilityname="layoutEngine"value="WebKit"/>
<capabilityname="layoutEngineVersion"value="${layoutVersion}"/>
</capabilities>
</browser>

这个文件本身引用另一个浏览器(Mozilla),这个模式将继续,直到到达根目录(直到浏览器文件中不再有parentID标记)。这就是浏览器文件将上面描述的层次结构转换为XML文件的方式。 (同时,您将注意到用户代理是如何通过标识标记与相应的输入进行匹配的(以及如何使用正则表达式将浏览器的版本考虑在内)。 一旦揭示了这种层次结构,我们就可以总结出ASP是如何推断一个浏览器的。NET Web API应用程序。 从客户机发出的请求中提取用户代理。将用户代理与根浏览器文件(这里是Default.browser)进行比较,如果它匹配,则使用与该文件关联的功能填充HttpBrowserCapabilities对象。然后将用户代理与浏览器文件可以拥有的每个子节点进行比较。如果其中一个匹配,则HttpBrowserCapabilities对象被新功能覆盖了。如果没有匹配,则不修改功能。以此类推,直到进程到达层次树的底部。 好消息是我们可以覆盖这个默认配置:我们所要做的就是在ASP的App_Browsers文件夹中添加定制的浏览器文件。NET Web API应用程序。然后我们可以改变默认行为,并正确地检测浏览器。稍后将对此进行更多介绍。 理论够多了,请编码! 我们之前看到Edge被错误地检测为Chrome。让我们用刚才的描述来解释为什么。 Edge用户代理是Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML,像Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10136。将此用户代理与默认值进行比较。由于没有匹配,浏览器被设置为Unknown 0.0。将此用户代理与M进行比较ozilla。用户代理匹配,因为它包含Mozilla。浏览器被设置为Mozilla 0.0。将此用户代理与IE进行比较。用户代理不匹配(它不包含Trident)。将此用户代理与WebKit进行比较。用户代理匹配,因为它包含AppleWebKit。浏览器被设置为Mozilla 0.0(名称没有overriden)。将此用户代理与Chrome进行比较。用户代理匹配,因为它包含Chrome。浏览器设置为Chrome 42。由于Chrome下没有浏览器文件,进程停止。 这就解释了为什么Edge被认为是Chrome。 那么,如何纠正这种行为呢?如前所述,可以通过添加自定义浏览器文件来实现这一点。 遵循下面的步骤: 在应用程序中添加App_Browsers文件夹(添加->添加ASP。网络文件夹→App_Browsers)。 在这个文件夹中,添加一个名为edge.browser的新文件。用以下内容填充此文件。 隐藏,复制Code

<browsers>
<browserid="Edge"parentID="Chrome">
<identification>
<userAgentmatch="Edge/(?'version'(?'major'\d+)(\.(?'minor'\d+)?)\w*)"/>
</identification> <capabilities>
<capabilityname="browser"value="Edge"/>
<capabilityname="majorversion"value="${major}"/>
<capabilityname="minorversion"value="${minor}"/>
<capabilityname="type"value="Edge${major}"/>
<capabilityname="version"value="${version}"/>
</capabilities> </browser>
</browsers>

更准确地说,我们只是告诉ASP。NET告诉我们,在这个过程中必须执行一个额外的步骤:NET Web API必须检查用户代理是否包含边。当我们声明圆括号是Chrome时,这个操作只有在所有要求都已经满足(Mozilla, AppleWebKit, Chrome)的情况下才会完成。 , , 我们可以看出,结果比以前好。 我们可以将同样的推理应用到其他浏览器上。例如: 对于SeaMonkey -加一个缝衣针。App_Browsers文件夹中的browser文件。 -填写以下内容。 隐藏,复制Code

<browsers>
<browserid="SeaMonkey"parentID="Firefox3Plus">
<identification>
<userAgentmatch="SeaMonkey/(?'version'(?'major'\d+)(\.(?'minor'\d+)?)\w*)"/>
</identification> <capabilities>
<capabilityname="browser"value="SeaMonkey"/>
<capabilityname="majorversion"value="${major}"/>
<capabilityname="minorversion"value="${minor}"/>
<capabilityname="type"value="SeaMonkey${major}"/>
<capabilityname="version"value="${version}"/>
</capabilities> </browser>
</browsers>

, , 对傲游浏览器 -加一个傲游。App_Browsers文件夹中的browser文件。 -填写以下内容。 隐藏,复制Code

<browsers>
<browserid="Maxthon"parentID="Chrome">
<identification>
<userAgentmatch="Maxthon/(?'version'(?'major'\d+)(\.(?'minor'\d+)?)\w*)"/>
</identification> <capabilities>
<capabilityname="browser"value="Maxthon"/>
<capabilityname="majorversion"value="${major}"/>
<capabilityname="minorversion"value="${minor}"/>
<capabilityname="type"value="Maxthon${major}"/>
<capabilityname="version"value="${version}"/>
</capabilities> </browser>
</browsers>

, , 所有其他浏览器以及那些将在未来几个月发布的浏览器都是如此。 但是生产过程中发生了什么呢? 浏览器检测是我们主要关心的问题。这就是我们执行上述指导方针的原因。但在生产过程中,我们很快就经历了一个非常奇怪和不可预测的现象。 例如,用户代理Mozilla/5.0 (Windows NT 6.0) AppleWebKit/537.36 (KHTML,像Gecko) Chrome/49.0.2623.87 Safari/537.36有时被识别为一个Chrome浏览器(这是正确的答案),但有时被检测为一个Maxthon浏览器。这场闹剧是什么意思? 我们最终发现了这个问题:不是在每个请求中实现上面描述的过程来找到浏览器,ASP。NET在相应浏览器的内存中保存了一个用户代理的临时键-值字典。 这是一个简单的例子: 访问者1与用户代理us1来到该网站。ASP。NET查看其缓存,以确定该用户代理是否已经注册。但事实并非如此,ASP。NET通过上面描述的过程(基于浏览器文件)来确定浏览器。然后使用此值更新缓存。下面是它的内容。 关键 价值 us1 browser1 访问者2与用户代理us2来到该网站。ASP。NET查看其缓存,以确定该用户代理是否已经注册。但事实并非如此,ASP。NET通过上面描述的过程(基于浏览器文件)来确定浏览器。然后使用此值更新缓存。以下是它的成分。 关键 价值 us1 browser1 2 browser2 使用用户代理us1的访问者3(与访问者1相同)访问本网站。ASP。NET查看其缓存,以确定该用户代理是否已经注册。在这种情况下,ASP。NET不需要重新计算浏览器,可以立即从缓存返回结果。 , 这种操作方式似乎先天非常强大,因为它可以提高性能。但是这个机制有一个小故障:字典中使用的键不是用户代理本身,而是前64个字符。所以: 当用户代理Mozilla/5.0 (Windows NT 6.0) AppleWebKit/537.36 (KHTML,如Gecko) Chrome/49.0.2623.87 Safari/537.36访问该站点时,缓存中使用的密钥是Mozilla/5.0 (Windows NT 6.0) AppleWebKit/537.36 (KHTML,如Ge)。检测到的浏览器是Chrome。因此,当用户代理的另一个访问者Mozilla / 5.0 (Windows NT 6.0) AppleWebKit / 537.36 (KHTML,像壁虎)傲游浏览器/ 4.4.8.1000 Chrome / 49.0.2623.87 Safari 537.36网站一秒钟后,再次使用的关键是Mozilla / 5.0 (Windows NT 6.0) AppleWebKit / 537.36 (KHTML,比如通用电气。由于密钥存储在缓存中,基于浏览器文件的经典进程不运行,浏览器被错误地识别为Chrome。 幸运的是,这个缓存键长度在web中是可配置的。config(在system. webgt中)部分)。添加以下代码: 隐藏,复制Code

<system.web>
<browserCapsuserAgentCacheKeyLength="256"/>
</system.web>

默认设置是接受用户代理的前64个字符,我们在这里将其配置为接受前256个字符。 事情b在此修改之后,ack恢复正常,浏览器最终都被正确地检测到。 走得更远 浏览器文件也可以用来检测平台,而不仅仅是浏览器。 总结 如果浏览器检测对您的业务至关重要,那么ASP。NET默认配置不充分,可能显示不正确的结果。 为了绕开这个问题,必须作出两项主要改变: -在App_Browsers文件夹中添加合适的浏览器文件 -修改web中的userAgentCacheKeyLength属性。配置文件 本文转载于:http://www.diyabc.com/frontweb/news19656.html