Ajax Cookie の同期について
前書き
この種の問題に遭遇すると、本当にどうしようもないです。
この記事は、そのような恥ずかしくてどうしようもない日を記録するだけです。皆様の退屈解消にご利用くださいT_T
あのシーンが再現されています
混乱した会話の後、私は落ち着いて「地雷を除去することしかできません」 」。 ロールバック、プロキシ、パケットキャプチャ、比較、単一要素のトラブルシューティング。 。 。 一連のコンボパンチを終えた後、最終的に欠陥を見つけるのに線香一本ほどかかりました。それは、ajax 同期コールバックに問題があることが判明しました。理不尽!そんなはずはありません!そのような操作はありますか? ! 問題の再発問題を一文で要約同僚:さあ!来て!オンラインで問題が発生しました! !
私: 一体何ですか?! ナナ?! 同僚: このリリースが原因ですか?
私: ロールバック!ロールバック! (なぜ食べようとしているのにチェーンを落とすのですか! 胃の世話ができません! すぐに確認してください)
...
ajax を使用して「同期」リクエストを行うと、このリクエストは
success
でこのターゲット Cookie を返します。 > コールバックが失敗しました!document.cookie
は、ajax の実行が完了するまで更新されませんsuccess
回调中读取此目标cookie 失败!ajax执行结束后document.cookie
才会被更新
影响范围
PC 端和 Android 端影响范围小,属于偶现。
IOS 端是重灾区,出来 Chrome 和 Safari 浏览器外的绝大多说浏览器都会出现此问题,并且 App 内置的 Webview 环境同样不能幸免。
在本同步请求回调内预读取本请求返回的 cookie 会产生问题。
半壁江山都沦陷了,我要这铁棒有何用!
追因溯果
小范围的兼容问题我姑且可以饶你,奈何你如此猖狂,怎能任你瞒天过海!
纵向对比
排除一些干扰项,还原其本质,我们分别用框架nej
,jQuery
和js
写几个相同功能的“同步” demo,走着瞧着。。
【nej.html】使用 NEJ 库
<!DOCTYPE html> <html> <head> <title>nej</title> <meta charset="utf-8" /> </head> <body> test <script src="http://nej.netease.com/nej/src/define.js?pro=./"></script> <script> define([ '{lib}util/ajax/xdr.js' ], function () { var _j = NEJ.P('nej.j'); _j._$request('/api', { sync: true, method: 'POST', onload: function (_data) { alert("cookie:\n" + document.cookie) } }); }); </script> </body> </html>
【jquery.html】使用 jQuery 库
<!DOCTYPE html> <html> <head> <title>jquery</title> <meta charset="utf-8" /> </head> <body> jquery <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script> <script> $.ajax({ url: '/api', async: false, method: 'POST', success: function (result) { alert("cookie:\n" + document.cookie) } }); </script> </body> </html>
【js.html】自己实现的 ajax 请求函数
<!DOCTYPE html> <html> <head> <title>JS</title> <meta charset="utf-8" /> </head> <body> js <script> var _$ajax = (function () { /** * 生产XHR兼容IE6 */ var createXHR = function () { if (typeof XMLHttpRequest != "undefined") { // 非IE6浏览器 return new XMLHttpRequest(); } else if (typeof ActiveXObject != "undefined") { // IE6浏览器 var version = [ "MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp", ]; for (var i = 0; i < version.length; i++) { try { return new ActiveXObject(version[i]); } catch (e) { return null } } } else { throw new Error("您的系统或浏览器不支持XHR对象!"); } }; /** * 将JSON格式转化为字符串 */ var formatParams = function (data) { var arr = []; for (var name in data) { arr.push(name + "=" + data[name]); } arr.push("nocache=" + new Date().getTime()); return arr.join("&"); }; /** * 字符串转换为JSON对象,兼容IE6 */ var _getJson = (function () { var e = function (e) { try { return new Function("return " + e)() } catch (n) { return null } }; return function (n) { if ("string" != typeof n) return n; try { if (window.JSON && JSON.parse) return JSON.parse(n) } catch (t) { } return e(n) }; })(); /** * 回调函数 */ var callBack = function (xhr, options) { if (xhr.readyState == 4 && !options.requestDone) { var status = xhr.status; if (status >= 200 && status < 300) { options.success && options.success(_getJson(xhr.responseText)); } else { options.error && options.error(); } //清空状态 this.xhr = null; clearTimeout(options.reqTimeout); } else if (!options.requestDone) { //设置超时 if (!options.reqTimeout) { options.reqTimeout = setTimeout(function () { options.requestDone = true; !!this.xhr && this.xhr.abort(); clearTimeout(options.reqTimeout); }, !options.timeout ? 5000 : options.timeout); } } }; return function (options) { options = options || {}; options.requestDone = false; options.type = (options.type || "GET").toUpperCase(); options.dataType = options.dataType || "json"; options.contentType = options.contentType || "application/x-www-form-urlencoded"; options.async = options.async; var params = options.data; //创建 - 第一步 var xhr = createXHR(); //接收 - 第三步 xhr.onreadystatechange = function () { callBack(xhr, options); }; //连接 和 发送 - 第二步 if (options.type == "GET") { params = formatParams(params); xhr.open("GET", options.url + "?" + params, options.async); xhr.send(null); } else if (options.type == "POST") { xhr.open("POST", options.url, options.async); //设置表单提交时的内容类型 xhr.setRequestHeader("Content-Type", options.contentType); xhr.send(params); } } })(); _$ajax({ url: '/api', async: false, type: 'POST', success: function (result) { alert("cookie:\n" + document.cookie) } }); </script> </body> </html>
三个文件都是一样的,在html 加载完之后发起一个同步请求,该请求会返回一个 cookie,在回调中将document.cookie
打印出来,检测是否已经在回调时写入的了 cookie。
下面使用 node 实现这个可写 cookie 的服务。
【serve.js】
var express = require("express"); var http = require("http"); var fs = require("fs"); var app = express(); var router = express.Router(); router.post('/api', function (req, res, next) { res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS"); res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With"); res.header("Set-Cookie", ["target=ccccccc|" + new Date()]); res.end('ok'); }); router.get('/test1', function (req, res, next) { fs.readFile("./nej.html", function (err, data) { res.end(data); }); }); router.get('/test2', function (req, res, next) { fs.readFile("./jquery.html", function (err, data) { res.end(data); }); }); router.get('/test3', function (req, res, next) { fs.readFile("./js.html", function (err, data) { res.end(data); }); }); app.use('/', router); http.createServer(app).listen(3000);
好了,万事大吉,run 一把
$ node serve.js
操作
我们依次执行如下操作,
使用 ios 端 QQ 浏览器,清空所有缓存
加载其中一个页面,观察是否有目标 cookie 输出
执行刷新操作,观察是否有目标 cookie 输出,比较 cookie 输出的时间戳,确认是否为上次 cookie 的同步结果而非本次请求获取的 cookie,
清空所有缓存,切换目标 html 文件,循环执行2,3,4步骤
结果
【nej.html】
纯净环境加载,未读取到目标 cookie
刷新加载,读取到上一次请求返回的 cookie
【jquery.html】
纯净环境加载,未读取到目标 cookie
刷新加载,未读取到目标 cookie
【js.html】
纯净环境加载,未读取到目标 cookie
刷新加载,未读取到目标 cookie
咦?结果不一样!使用 nej 的第二次加载读取到了第一次 cookie。其他的两次均为获取到。
原因
nej 依赖框架的加载是异步的,当同步请求发起时,dom 已经加载完毕,回调相应时,document.cookie
已经呈“ready”状态,可读可写。但请求依然获取不到自身返回携带的 cookie。
而其他两种加载的机制阻塞了 dom 的加载,导致同步请求发起时,dom 尚未加载完成,回调相应时,document.cookie
iOS は最も影響を受けやすい領域です。Chrome と Safari を除くほとんどのブラウザではこの問題が発生し、アプリの組み込み Webview 環境も影響を受けません。
国の半分が崩壊したのに、この鉄の棒は何の役に立つのでしょう!
原因と結果を追跡小規模な互換性の問題については許せますが、あなたはとても傲慢です、どうやってそれを隠すことができますか?
- 垂直比較 いくつかの干渉項目を排除し、その本質を復元するために、フレームワーク
nej
、jQuery
、およびjs
を使用して、いくつかのフレームワークを作成します。同一 「同期」機能のデモです。様子を見てみましょう。 。
$('document').click(function () { // TODO 发起同步请求 });
- 【js.html】自作したajaxリクエスト関数
rrreee
htmlで読み込んだ後の3つのファイルは同じです次に、同期リクエストを開始します。これにより、コールバック内で Cookie が返され、コールバック中に Cookie が書き込まれたかどうかを確認します。 - 以下では、ノードを使用してこの書き込み可能な Cookie サービスを実装します。
【serve.js】
rrreee OK、すべて問題ありません。
_$ajax({ url: '/api', async: false, type: 'POST', success: function (result) { setTimeout(function(){ // do something 在此处获取 cookie 操作是安全的 },0) } });
操作を実行します
- 次の操作を順番に実行します。
- iOS で QQ ブラウザを使用します。 、すべてのキャッシュをクリアします🎜🎜🎜🎜 ページの 1 つをロードし、ターゲットの Cookie 出力があるかどうかを確認します🎜🎜🎜🎜 更新操作を実行し、ターゲットの Cookie 出力があるかどうかを確認し、Cookie 出力のタイムスタンプを比較して確認します最後の Cookie の同期結果であるかどうか このリクエストで取得した Cookie の代わりに、🎜🎜🎜🎜すべてのキャッシュをクリアし、対象の HTML ファイルを切り替え、手順 2、3、4 をループします🎜🎜
document.cookie
はすでに「準備完了」になっています。状態であり、読み書き可能です。ただし、リクエスト自体は依然として返される Cookie を取得できません。 🎜🎜🎜 🎜他の 2 つのロード メカニズムは DOM のロードをブロックするため、同期リクエストが開始されたときに DOM はロードされず、
document.cookie
はまだ書き込み不可能です。 🎜🎜単一要素制御🎜🎜上記のHTMLファイルのロジックを修正していきます。 🎜ドキュメントがクリックされてトリガーされるまで同期リクエストを遅らせます。 🎜以下🎜rrreee🎜はまだ上記の実行手順です。結果を見てみましょう🎜🎜結果🎜🎜[nej.html]🎜🎜🎜🎜純粋な環境の読み込み、ターゲットのCookieは読み取られませんでした🎜🎜🎜🎜読み込みを更新します、前のリクエストによって返された Cookie を読み取ります🎜🎜🎜🎜[jquery.html]🎜🎜🎜🎜純粋な環境の読み込み、ターゲットの Cookie は読み取られません🎜🎜🎜🎜ロードを更新し、前のリクエストによって返された Cookie を読み取ります🎜🎜 🎜🎜【js.html】🎜🎜🎜🎜純粋な環境読み込み、ターゲットCookieは読み込まれません🎜刷新加载,读取到上一次请求返回的 cookie
结果和预期一样,本次请求无法获取本期返回的目标 cookie,请求回调执行后,目标cookie才会更新到document.cookie
上。
特例
在执行以上操作是,发现,【jquery.html】的执行结果时不时会有两种结果
纯净环境加载,未读取到目标 cookie
刷新加载,读取到上一次请求返回的 cookie
另外一种几率较小,但也会出现纯净环境加载,读取到目标 cookie
刷新加载,读取到目标 cookie
产生原因
一言不合看源码
我们在 jquery 的源码中看到,jquery 的success
回调绑定在了 onload
事件上
https://code.jquery.com/jquery-3.2.1.js :9533行
而我自己实现的和 nej 的实现均是将success
回调绑定在了 onreadystatechange
事件上,唯一的区别就在于此
一个正向的 ajax 请求,会先触发两次onreadystatechange
,在触发onload
,或许原因在于document.cookie
的同步有几率在onload
事件触发前完成??I'm not sure.
问题结论
在 PC 端,Android 端,IOS 端Chrome、Safari 浏览器环境下,ajax 的同步请求的回调方法中,取到本请求返回的 cookie 失败几率低
IOS 端,QQ 浏览器、App 内置Webview浏览器环境下,失败率极高。
解决方案
只有问题没有方案的都是在耍流氓!
方案1 - 明修栈道暗度陈仓
将回调方法中的 cookie 获取方法转化为异步操作。
_$ajax({ url: '/api', async: false, type: 'POST', success: function (result) { setTimeout(function(){ // do something 在此处获取 cookie 操作是安全的 },0) } });
方案2 - 不抵抗政策
没有把握的方案,我们是要斟酌着实施的。
如果你不能100%却被操作的安全性,那并不建议你强行使用 ajax 的同步操作,很多机制并不会像我们自以为是的那样理所应当。
以上がAjax Cookie の同期についての詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









タイトル: jQuery AJAX リクエストの 403 エラーを解決する方法とコード例。403 エラーは、サーバーがリソースへのアクセスを禁止するリクエストを指します。このエラーは通常、リクエストにアクセス許可がないか、サーバーによって拒否されたために発生します。 jQueryAJAX リクエストを行うときにこのような状況に遭遇することがありますが、この記事ではこの問題の解決方法とコード例を紹介します。解決策: 権限を確認します。まず、要求された URL アドレスが正しいことを確認し、リソースにアクセスするための十分な権限があることを確認します。

jQuery は、クライアント側の開発を簡素化するために使用される人気のある JavaScript ライブラリです。 AJAX は、Web ページ全体をリロードせずに、非同期リクエストを送信し、サーバーと対話するテクノロジーです。ただし、jQuery を使用して AJAX リクエストを行うと、403 エラーが発生することがあります。 403 エラーは通常、セキュリティ ポリシーまたは権限の問題が原因で、サーバーによってアクセスが拒否されたエラーです。この記事では、jQueryAJAX リクエストで 403 エラーが発生した場合の解決方法について説明します。

ますます多くのユーザーが win11 システムにアップグレードし始めています。各ユーザーの使用習慣が異なるため、多くのユーザーは依然として ie11 ブラウザーを使用しています。では、win11 システムで ie ブラウザーを使用できない場合はどうすればよいでしょうか? Windows11はIE11をまだサポートしていますか?解決策を見てみましょう。 win11でie11ブラウザが使えない問題の解決策 1. まず、スタートメニューを右クリックし、「コマンドプロンプト(管理者)」を選択して開きます。 2. 開いたら、「Netshwinsockreset」と直接入力し、Enter キーを押して確定します。 3. 確認後、「netshadvfirewallreset&rdqu」と入力します。

インターネットの普及により、ブラウザを使用してインターネットを閲覧することが生活様式になりました。ブラウザを日常的に使用する中で、オンラインショッピング、ソーシャルネットワーキング、電子メールなど、アカウントのパスワードを入力する必要がある場面に遭遇することがよくあります。この情報は、次回アクセスするときに再度入力する必要がないようにブラウザによって記録される必要がありますが、このような場合に Cookie が役に立ちます。クッキーとは何ですか? Cookie とは、サーバーからユーザーのブラウザに送信され、ローカルに保存される小さなデータ ファイルを指し、一部の Web サイトでのユーザーの行動が含まれています。

jQueryAJAX エラー 403 の問題を解決するにはどうすればよいですか? Web アプリケーションを開発する場合、非同期リクエストを送信するために jQuery がよく使用されます。ただし、jQueryAJAX の使用時に、サーバーによってアクセスが禁止されていることを示すエラー コード 403 が発生する場合があります。これは通常、サーバー側のセキュリティ設定が原因ですが、回避する方法があります。この記事では、jQueryAJAX エラー 403 の問題を解決する方法と具体的なコード例を紹介します。 1.作る

PHP と Ajax を使用してオートコンプリート候補エンジンを構築します。 サーバー側スクリプト: Ajax リクエストを処理し、候補を返します (autocomplete.php)。クライアント スクリプト: Ajax リクエストを送信し、提案を表示します (autocomplete.js)。実際のケース: HTML ページにスクリプトを組み込み、検索入力要素の識別子を指定します。

Ajax を使用して PHP メソッドから変数を取得することは、Web 開発では一般的なシナリオであり、Ajax を使用すると、データを更新せずにページを動的に取得できます。この記事では、Ajax を使用して PHP メソッドから変数を取得する方法と、具体的なコード例を紹介します。まず、Ajax リクエストを処理し、必要な変数を返すための PHP ファイルを作成する必要があります。以下は、単純な PHP ファイル getData.php のサンプル コードです。

最近、多くの win10 ユーザーが、コンピューターのブラウザーを使用するときに、IE ブラウザーが常に自動的にエッジ ブラウザーにジャンプすることに気付きました。このサイトでは、win10でIEを開いたときに自動的にエッジにジャンプして閉じる方法をユーザーに丁寧に紹介しましょう。 1. Edge ブラウザにログインし、右上隅にある [...] をクリックして、ドロップダウン設定オプションを探します。 2. 設定を入力したら、左側の列の「デフォルトのブラウザ」をクリックします。 3. 最後に、互換性で、Web サイトが IE モードで再ロードされないようにチェックボックスをオンにし、IE ブラウザを再起動します。
