J'ai remarqué que Chrome (64.0.3282.137) sur mon téléphone (OnePlus 3, Android 8.0.0) envoie des agents utilisateur légèrement différents lors de la demande d'une page Web par opposition à la demande via ajax.
Cet agent utilisateur est envoyé lors de la demande d'une page Web:
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
Cet agent utilisateur est envoyé lors d'un appel ajax et est également renvoyé lors de l'appel 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
Différence: ONEPLUS A3003
Pouvez-vous me dire pourquoi le modèle est inclus dans les appels natifs, mais pas dans les appels ajax?
Informations supplémentaires: Lorsque la fonction "Demander un site de bureau" est activée, l'agent d'utilisateur est
Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Safari/537.36
dans les deux cas.
J'ai analysé le code source du chrome pour obtenir des informations. J'ai été capable d'atteindre seulement un niveau avec mes capacités de novice en c ++.
L'agent utilisateur du client ou de la plate-forme est détecté dans ce bloc de code (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);
}
Vous pouvez voir BuildOSCpuInfo () dans le bloc de code qui s’occupe de l’ajout des informations OS realted en fonction des plates-formes que vous pouvez trouver ici.
std::string Android_build_codename = base::SysInfo::GetAndroidBuildCodename();
std::string Android_device_name = base::SysInfo::HardwareModelName(); // this line in particular adds the ONEPLUS A3003
Mais cette fonction (BuildUserAgentFromProduct ()) n’est pas utilisée directement dans le module réseau qui s’occupe de l’envoi des requêtes http.
Lorsque j'ai étudié le code du module net (http), je me suis rendu compte qu'ils obtenaient le useragent * et le traitaient via une série de manipulations de chaînes et de fonctionnalités d'ajustement des espaces. AddHeadersFromString () dans http_request_headers.cc est l'interface via laquelle la chaîne useragent est ajoutée à l'en-tête de la demande.
Note *: Mais je pense que les données d'en-tête ne proviennent pas de useragent.cc, car je ne parviens pas à trouver les appels pour cette fonction nulle part. Mais je peux me tromper ici.
** Je crois que c'est à cet endroit que la valeur de OSInfo est modifiée. Tout caractère d'espacement non reconnu ou dans un format incorrect, alors prévu à l'origine, peut donner ce résultat.
Note **: Je ne pouvais pas tester la déclaration ci-dessus et la prouver, car String est utilisé dans Chromium et est entouré d'un wrapper au nom de StringPiece (* wrapper est simplement un terme que j'utilise, techniquement, il peut être utilisé. appelé d’une manière différente que je ne connais pas). Et je ne sais pas comment écrire le code en c ++ pour StringPiece.
Mais un exemple très simple de la façon dont cela peut mal tourner est donné ci-dessous.
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
Venir à la raison pour laquelle la chaîne d'agent utilisateur initiale a la valeur et la requête http suivante n'a pas la valeur, réside dans l'architecture de l'application Chrome dans Android. Lorsque la page est chargée initialement, les valeurs sont définies par l'application Chrome (une très grande base de code Java. Mais je pense que le fichier de base que nous devons voir est LoadUrlParams.Java), qui a une implémentation différente de l'envoi de la requête http (ici L'agent utilisateur n'est pas coupé par le même module net (http) mais est pris en charge par l'implémentation Java), cela ne se produit que lors du tout premier chargement. Mais tout autre appel suivant utilise le module net (http) du navigateur.
Liens de référence de fichier: https://cs.chromium.org/chromium/src/content/common/user_agent.cc?sq=package:chromium&dr=CSs&l=80
J'inclus simplement cette réponse pour donner l'une des raisons pour lesquelles le problème aurait pu se produire. Si j'ai plus de temps, je verrai si je peux faire un test et le prouver. Une note finale cette réponse ne donne aucune solution pour résoudre le problème. Cela donne juste la raison de la cause.
[Mettre à jour]
Une astuce très économique consiste à vérifier si navigator.useragent a la valeur oneplus et à définir les en-têtes ajax sur la demande et à l'envoyer. Cela annulera le mécanisme du navigateur consistant à ajouter l'en-tête de l'agent d'utilisateur.
XMLHttpRequest.setRequestHeader(header, value)
Dans le premier utilisateur user, le navigateur identifie le périphérique en tant que périphérique mobile en modifiant le userAgent avant de faire la demande; d'où le ONEPLUS A3003
. Dans la seconde cependant, à cause de la spécification w3 (Trouvez-la ici) , vous ne pouvez pas modifier le userAgent; d'où l'omission de ONEPLUS A3003
.
Lorsque vous utilisez la fonctionnalité "Demander un site de bureau", il n'est pas nécessaire de modifier userAgent par le navigateur. Vous obtenez donc le même userAgent.
REMARQUE: L'agent utilisateur par défaut pour ce navigateur Chrome est: 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