Javascript user-agent (ajax) отличается от отправленного user-agent при запросе веб-сайта

я заметил, что Chrome (64.0.3282.137) на моем телефоне (OnePlus 3, Android 8.0.0) отправляет немного разные пользовательские агенты при запросе веб-страницы в отличие от запроса через ajax.

этот user-agent отправляется при запросе веб-страницы:

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

этот пользовательский агент отправляется с 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

отличия: ONEPLUS A3003

можете ли вы сказать, почему модель входит в родные вызовы, но не в ajax-вызовы?

дополнительная информация: с"запрос рабочего стола сайта" -функция включена агент пользователя Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Safari/537.36 в обоих случаях.

2 ответов


Я проанализировал исходный код chromium, чтобы получить некоторые идеи. Я смог добраться только до некоторого уровня с моими начинающими способностями на c++.

агент пользователя клиента или платформы обнаружен в этом блоке кода (файл: 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);
}

вы можете увидеть BuildOSCpuInfo () в блоке кода, который заботится о добавлении ОС realted информации на основе платформ, которые можно найти здесь

std::string android_build_codename = base::SysInfo::GetAndroidBuildCodename();
std::string android_device_name = base::SysInfo::HardwareModelName(); // this line in particular adds the ONEPLUS A3003

но эта функция (BuildUserAgentFromProduct ()) является не используется непосредственно в модуле net, который заботится о отправке http-запросов.

когда я исследовал код для модуля net (http), я вижу, что они получают useragent* и обрабатывают его с помощью ряда манипуляций со строками и функций обрезки пробела. AddHeadersFromString () в http_request_headers.cc является интерфейсом, через который строка useragent добавляется в заголовок запроса.

Примечание*: но я думаю, что данные заголовка не от useragent.cc, потому что я не могу найти вызовы для этой функции в любом месте. Но здесь я могу ошибаться.

* * Я считаю, что это место, где значение для OSInfo изменяется. Любой символ пробела, который не распознается или в неправильном формате, который изначально предназначался, может дать этот результат.

примечание**: Я не мог проверить приведенное выше утверждение и доказать его, потому что строка, используемая в Chromium, имеет обертку вокруг нее во имя StringPiece( * wrapper - это просто термин, который я использую, технически его можно назвать по-другому, чего я не знаю.). И я не знаю, как написать код на c++ для StringPiece.

но очень простой пример, как это может пойти не так, приведен ниже.

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

переход к причине, по которой начальная строка агента пользователя имеет значение, а последующий http-запрос не имеет значения, лежит с архитектура приложения chrome в android. Когда страница загружается изначально, значения фактически устанавливаются приложением chrome (очень большая база кода java, но я думаю, что основной файл, который нам нужно увидеть, - это LoadUrlParams.java), который имеет другую реализацию отправки http-запроса (здесь useragent не обрезается тем же модулем net(http), а заботится о его реализации Java), это происходит только во время самой первой загрузки. Но любые другие последующие вызовы используют браузер модуль net (http).

Ссылка На Файл связи: 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/content/public/android/java/src/org/chromium/content_public/browser/LoadUrlParams.java?q=createLoadDataParamsWithBaseUrl&dr=CSs

Я просто включая этот ответ, чтобы дать одну из причин, по которой могла возникнуть проблема. Если у меня будет еще немного времени, я посмотрю, смогу ли я как-то провести тест и доказать это. Последнее замечание этот ответ не дает никакого решения для устранения проблемы. Это просто дает причину для причины.

[обновление]

один очень дешевый трюк, чтобы увидеть, если навигатор.useragent имеет значение oneplus и устанавливает заголовки ajax в запросе и отправляет его. Это переопределит механизм браузера добавление заголовка агента пользователя.

XMLHttpRequest.setRequestHeader(header, value)

в первом userAgent браузер идентифицирует устройство как мобильное устройство, изменяя userAgent перед выполнением запроса; следовательно,ONEPLUS A3003. Во втором, однако, из-за спецификации w3 (найти его здесь), вы не можете изменить userAgent; следовательно, пропуск ONEPLUS A3003.

когда вы используете функцию "запрос рабочего стола", нет необходимости в модификации userAgent браузером, следовательно, вы получаете тот же userAgent.

примечание: что по умолчанию userAgent для этого браузера Chrome: 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