问题描述
我注意到我的手机上的Chrome(64.0.3282.137)(OnePlus 3,Android 8.0.0)在请求网页时发送的用户代理略有不同,而不是通过ajax请求。
此用户代理在请求网页时发送:
Mozilla / 5.0(Linux; Android 8.0.0; ONEPLUS A3003 Build / OPR6.170623.013)AppleWebKit / 537.36(KHTML,如Gecko)Chrome / 64.0.3282.137 Mobile Safari / 537.36
代理发送ajax调用,并在调用 navigator.userAgent
时返回:
Mozilla / 5.0(Linux; Android 8.0.0; Build / OPR6.170623.013)AppleWebKit / 537.36(KHTML,如Gecko)Chrome / 64.0.3282.137 Mobile Safari / 537.36
区别: ONEPLUS A3003
你能告诉我为什么包含模型在本地调用中,但不在ajax调用中?
我分析了铬源代码以获得一些见解。我只能在c ++中获得一些新手能力。
客户端或平台的用户代理在此代码块中检测到(File:useragent。
std :: string BuildUserAgentFromProduct(const std :: string& product){
std :: string os_info;
base :: StringAppendF(
& os_info,
%s%s,
getUserAgentPlatform()。c_str(),
BuildOSCpuInfo()。c_str ));
返回BuildUserAgentFromOSAndProduct(os_info,product);
$ b您可以在代码块中看到BuildOSCpuInfo(),该代码块负责添加os基于平台可以在这里找到的信息
$ b $ pre $ std :: string android_build_codename = base :: SysInfo :: GetAndroidBuildCodename() ;
std :: string android_device_name = base :: SysInfo :: HardwareModelName(); //这一行特别添加了ONEPLUS A3003
但是这个函数(BuildUserAgentFromProduct())没有被使用直接在网络模块中,负责发送http请求。
当我调查网络(http)模块的代码时,我发现他们得到了useragent *并通过一系列字符串操作和空白裁剪功能对其进行处理。 http_request_headers.cc中的AddHeadersFromString()是将useragent字符串添加到请求标头的接口。
注意:但我认为标头数据不是来自useragent .cc,因为我无法在任何地方找到此功能的调用。但我可能在这里是错的。
**我相信这是OSInfo的值被修改的地方。任何未被识别的空白字符或者最初打算的错误格式都可以给出这个结果。注意**:我无法测试上述语句并证明它,因为在Chromium中使用的字符串以StringPiece名义包装它( *包装只是我使用的一个术语,从技术上讲,它可以用我不知道的不同方式调用)。我不知道如何在C ++中为StringPiece编写代码。
但是,下面给出了一个非常简单的错误示例。
int main()
{
std :: string s =ONEPLUS \rA3003\rBuild / OPR6。 170623.013\" ;
std :: string delimiter =\r\\\
; //这是铬源代码中使用的分隔符。
std :: string token = s.substr(0,s.find(delimiter,0));
std :: cout<<令牌<<的std :: ENDL;
返回0;
}
为了说明初始用户代理字符串的原因该值和随后的http请求没有价值,与android应用程序中的chrome应用程序的体系结构有关。当页面最初加载时,这些值实际上是由chrome应用程序(一个非常大的java代码库)设置的(但我认为我们需要看到的核心文件是LoadUrlParams.java),它具有发送http请求的不同实现(此处useragent并不是由同一个网络(http)模块修剪而是由Java实现部门来处理),这只发生在第一次加载时。但任何其他后续调用都使用浏览器的网络(http)模块。
文件参考链接:
我只是将这个答案包含在可能出现问题的原因之一中。如果我有更多的时间,我会看看我是否可以通过某种方式进行测试并证明这一点。
一个最后的注意这个答案没有给出任何解决方案来解决这个问题。它只是给出了原因。
[更新]
一个非常便宜的窍门是看看是否navigator.useragent具有oneplus值并在请求上设置一个jax头并发送它。这将覆盖浏览器添加用户代理标头的机制。
XMLHttpRequest.setRequestHeader(header,value)
I noticed that Chrome (64.0.3282.137) on my phone (OnePlus 3, Android 8.0.0) sends slightly different user-agents when requesting a webpage in contrast to requesting via ajax.
This user-agent is sent when requesting a webpage:
Mozilla/5.0 (Linux; Android 8.0.0; ONEPLUS A3003 Build/OPR6.170623.013) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36
This user-agent is sent making an ajax-call and is also returned when calling navigator.userAgent
:
Mozilla/5.0 (Linux; Android 8.0.0; Build/OPR6.170623.013) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36
Difference: ONEPLUS A3003
Can you tell my why the model is included in the native calls, but not in ajax-calls?
I analyzed the chromium source code to get some insights. I was able to get only to some level with my novice abilities in c++.
User agent of the client or the platform is detected in this code block (File: useragent.cc).
std::string BuildUserAgentFromProduct(const std::string& product) {
std::string os_info;
base::StringAppendF(
&os_info,
"%s%s",
getUserAgentPlatform().c_str(),
BuildOSCpuInfo().c_str());
return BuildUserAgentFromOSAndProduct(os_info, product);
}
You can see BuildOSCpuInfo() in the code block which takes care of adding the os realted informations based on platforms which can be found here
std::string android_build_codename = base::SysInfo::GetAndroidBuildCodename();
std::string android_device_name = base::SysInfo::HardwareModelName(); // this line in particular adds the ONEPLUS A3003
But this function(BuildUserAgentFromProduct()) is not used directly in the net module which takes care of sending the http requests.
When I investigated the code for the net(http) module I see that they are getting the useragent* and processing it through a series of string manipulations and white space trimming functionalities. AddHeadersFromString() in http_request_headers.cc is the interface through which the useragent string is added to the request header.
Note*: But I think the header data is not from useragent.cc, because I am not able to find the calls for this function anywhere. But I might be wrong here.
**I believe that this is the place the value for the OSInfo is getting modified. Any whitespace character that is not recognized or in a wrong format then originally intended can give this result.
Note**: I couldn't test the above statement and prove it, because the String that is used in Chromium has a wrapper around it in the name of StringPiece( *wrapper is just a term that I am using, technically it can be called in a different way which I don't know.). And I don't know how to write the code in c++ for StringPiece.
But a very simple example of how it can go wrong is given below.
int main()
{
std::string s = " ONEPLUS\rA3003\rBuild/OPR6.170623.013";
std::string delimiter = "\r\n"; //this is the delimeter used in chromium source code.
std::string token = s.substr(0, s.find(delimiter,0));
std::cout << token << std::endl;
return 0;
}
https://www.onlinegdb.com/SkTrbFJDz
Coming to the reason why the initial user agent string is having the value and the subsequent http request doesnt have the value, lies with the architecture of chrome app in android. When the page is loaded initially the values are actually set by the chrome app (a very big java code base But I think the core file that we need to see is LoadUrlParams.java) which has a different implementation of sending the http request (here the useragent is not trimmed by the same net(http) module instead its taken care by the Java Implementation), this happens only during the very first load. But any other subsequent calls uses the browser's net(http) module.
File Reference links:https://cs.chromium.org/chromium/src/content/common/user_agent.cc?sq=package:chromium&dr=CSs&l=80
I am just including this answer to give one of the reasons where the problem might have occurred. If I have some more time I will see if I can run a test somehow and prove this.One Final Note this answer doesn't give any solution to fix the problem. It just gives the reason for the cause.
[Update]
One very cheap trick is to see if navigator.useragent has the oneplus value and set ajax headers on the request and send it. This will override the browser's mechanism of adding the user agent header.
XMLHttpRequest.setRequestHeader(header, value)
这篇关于Javascript用户代理(ajax)与请求网站时发送的用户代理不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!