简体   繁体   English

Javascript user-agent(ajax)与请求网站时发送的用户代理不同

[英]Javascript user-agent (ajax) different to sent user-agent when requesting website

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. 我注意到我的手机上的Chrome(64.0.3282.137)(OnePlus 3,Android 8.0.0)在请求网页时发送的用户代理略有不同,与通过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 : 发送此用户代理进行ajax调用,并在调用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 差异: ONEPLUS A3003

Can you tell my why the model is included in the native calls, but not in ajax-calls? 你能告诉我为什么模型包含在本机调用中,而不是在ajax调用中吗?

Additional information: With the "Request desktop site"-feature enabled the user agent is Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Safari/537.36 in both cases. 附加信息:启用“请求桌面站点”功能后,用户代理为Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Safari/537.36

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++. 我能用c ++中的新手能力达到某种程度。

User agent of the client or the platform is detected in this code block (File: useragent.cc). 在此代码块(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 您可以在代码块中看到BuildOSCpuInfo(),它负责根据可以在这里找到的平台添加os实际信息。

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. 但是这个函数(BuildUserAgentFromProduct())不直接用在负责发送http请求的网络模块中。

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. 当我调查net(http)模块的代码时,我看到他们正在获得useragent *并通过一系列字符串操作和空白区域修剪功能来处理它。 AddHeadersFromString() in http_request_headers.cc is the interface through which the useragent string is added to the request header. http_request_headers.cc中的AddHeadersFromString()是将useragent字符串添加到请求标头的接口。

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. 注意*:但我认为标题数据不是来自useragent.cc,因为我无法在任何地方找到对此函数的调用。 But I might be wrong here. 但我可能在这里错了。

**I believe that this is the place the value for the OSInfo is getting modified. **我相信这是OSInfo的价值被修改的地方。 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.). 注意**:我无法测试上述语句并证明它,因为Chromium中使用的String在StringPiece的名称中有一个包装器(* wrapper只是我正在使用的术语,从技术上讲它可以是以不同的方式打电话,我不知道。) And I don't know how to write the code in c++ for StringPiece. 我不知道如何用C ++编写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 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. 由于初始用户代理字符串具有该值并且后续http请求没有该值的原因在于android中的chrome app架构。 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. 当最初加载页面时,值实际上是由chrome应用程序设置的(​​一个非常大的java代码库但我认为我们需要看到的核心文件是LoadUrlParams.java),它具有发送http请求的不同实现(这里useragent不是由相同的net(http)模块修剪而是由Java实现来处理,这只在第一次加载时发生。 But any other subsequent calls uses the browser's net(http) module. 但任何其他后续调用都使用浏览器的net(http)模块。

File Reference links: https://cs.chromium.org/chromium/src/content/common/user_agent.cc?sq=package:chromium&dr=CSs&l=80 文件参考链接: https//cs.chromium.org/chromium/src/content/common/user_agent.cc?sq = package: chromium&dr = CSs&l = 80

https://cs.chromium.org/chromium/src/net/http/http_request_headers.cc?type=cs&q=AddHeadersFromString&l=155 https://cs.chromium.org/chromium/src/net/http/http_request_headers.cc?type=cs&q=AddHeadersFromString&l=155

https://cs.chromium.org/chromium/src/content/public/android/java/src/org/chromium/content_public/browser/LoadUrlParams.java?q=createLoadDataParamsWithBaseUrl&dr=CSs https://cs.chromium.org/chromium/src/content/public/android/java/src/org/chromium/content_public/browser/LoadUrlParams.java?q=createLoadDataParamsWithBaseUrl&dr=CSs

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. 一个非常便宜的技巧是查看navigator.useragent是否具有oneplus值并在请求上设置ajax标头并发送它。 This will override the browser's mechanism of adding the user agent header. 这将覆盖浏览器添加用户代理标头的机制。

XMLHttpRequest.setRequestHeader(header, value)

In the first userAgent, the browser identifies the device as a mobile device by modifying the userAgent before making the request; 在第一个userAgent中,浏览器通过在发出请求之前修改userAgent将设备识别为移动设备; hence the ONEPLUS A3003 . 因此ONEPLUS A3003 In the second however, due w3 specification (Find it here) , you cannot modify the userAgent; 但是在第二种情况下,由于w3规范(在此处查找) ,您无法修改userAgent; hence the omission of ONEPLUS A3003 . 因此省略了ONEPLUS A3003

When you use the "Request desktop site" feature, there is no need for modification of userAgent by the browser, hence you get the same userAgent. 当您使用“请求桌面站点”功能时,浏览器无需修改userAgent,因此您将获得相同的userAgent。

NOTE: That the default userAgent for that Chrome browser is: 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 注意:该Chrome浏览器的默认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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM