フロントエンドにマルチnodeサービスを導入
5314 ワード
ドキュメントの目的:
複数のサーバにフロントエンドコードを配備できることを実現する.
システムせっけい
フロントエンドnodeバックエンド(java)
Nodeレイヤは、(1)サービス側レンダリング、(2)restApiインタフェース処理
テクノロジーアーキテクチャ
react + redux + node + express
改変前の検証ロジック
tokenチェックの採用
バックエンド(java側)はtokenとユーザ情報をdata形式でフロントエンド(node層)に送り、フロントエンド(node層)はsessionに保存され、restApiインタフェースではsessionからこのtokenを取得してreq.headerに保存し、sessionからユーザ名、企業であるかどうかなどのフィールドを特定の必要なインタフェースに置くユーザ情報はセッションに保存されます.セッションはexpress-session、すなわちnodeサーバに保存されます
解決策(passに落とされた)セッション方式がまだ使用されている場合.ソリューション:ip_hash法で解決する. という案は、いくつかの点背のユーザーを放棄した.ユーザaがログインすると、ユーザ情報がサーバ1に保存される.このときサーバ1が停止しました.ユーザaは要求を送信し、tokenを取得できず、送信されたのは空またはundefinedであると考えられる.するとバックエンドは403に戻り、期限切れやタイムアウトなどしてログインを飛び出します. このシーンが納得できれば原則として可能です.テスト環境にも異常は発見されなかったが、オンライン上にユーザーのフィードバックシリアル番号があり、影響が大きすぎると感じ、すぐにロールバックし、問題は再現されなかった .それから今の問題は、データベースの操作記録を見て、n(少なくとも>10)の多くのユーザーの操作はすべて問題がなくて、1人のユーザーが彼のシリアル番号をフィードバックしましたが、私たちの開発とテストはすべて問題を再現することができなくて、それからロールバックで終わりました. いったいなぜシリアルナンバーになったのか、病気なく終わったのか......
シリアル番号の問題がある場合、sessionのnodeレイヤでのキャッシュによる可能性が高いと推測されます.
今、この需要を2回します.前回のバージョンを再オンラインにしますか、それとも考えを変えますか.ドキドキ・・・
(PS:一番怖いのは需要が難しすぎて開発できないのではなく、まったく再現できない問題で、手がつけられないのです.
質問を出す
やり直す以上、雨露を均一につけ、すべてのユーザーの世話をしなければならない.どうすればいいですか.
複数のサーバを配備し、ユーザー情報をnodeサーバに保存できない.
理由は簡単で、1台のサーバが停止し、オンラインになった場合、ユーザaのログイン情報が停止されたサーバに保存された場合、そのユーザのログインに異常が発生し、例えばログインを終了するなどである.
では、どこに保存すればいいのでしょうか.
シナリオは、Redisなどのデータベースとフロントエンドの2つです.
Redisは捨てられた
Redisは高性能key-valueデータベースその利点の1つは、マルチプロセスで共有でき、バックアップとリカバリメカニズムが完備されていることです.に似合うようです
しかし、ユーザ情報の処理にRedisを使用するだけでは「不器用」すぎるさらにtokenの検証はバックエンド(javaエンド)で維持され、フロントエンドは要求を送信する際にユーザ情報(tokenを含む)を持っているだけで、データベース依存を追加する必要はない.
3と4の2点を統合したので、この案は放棄された.
フロントエンドに保存されたスキーマ
store(実際にはredux-store)に保存するクッキーに保存する.
以下、この2つの案について、この問題を解決する考え方を詳しく紹介します.
シナリオの検討
シナリオ1:store(破棄)
ログインに成功すると、ユーザー情報はstoreに保存されます.各restApiインタフェースは、storeからのユーザ情報を取得する.
1台のサーバで正常に動作する複数のサーバの場合、apiインタフェースごとにnodeレイヤでstoreからユーザ情報を取得できないことが判明し、undefined として印刷される.
これも理解できます.結局storeはフロントエンドであり、node層はサーバ側に属し、単一のサーバは、キャッシュによるものと推測することができる(検証されていない、推測のみ) シナリオ2:storeストレージ方式の継続(廃棄)
次に、フロントエンドのstoreでユーザ情報を取得し、インタフェースに追加することを考慮する.
1つの理由:username、email、iscompanyなどのフィールドのrestApiインタフェースを単独で変更することに関連する.
2つの理由:tokenの生成ルールは、ipを使用します.つまりipは必ず送らなければならないので、各インタフェースはipというパラメータを送信しなければならず、ユーザーの習慣に合わない.機能が実現しても.
特に第2の原因はを排除した.
シナリオ3:クッキー(廃棄)は、ユーザ情報とtokenをクッキーで保存することを考慮する. ユーザログインに成功すると、フロントエンド(node)はバックエンドから戻るユーザ情報(tokenを含む)を受け取り、クッキーに 保存する.新しい問題がまた来ました.同じブラウザがクッキーを共有しているからです. つまり、2つのアカウントaとbにログインすると、クッキーはbになるので、aアカウントはbに更新しなければなりません.そうしないと、アカウント間のデータが混乱しやすくなります. ソリューションは、ユーザ動作actionとコード実行reducerの間に、現在のクッキーと現在のページstoreのtokenが一致しているかどうかをキャプチャし、一致していない場合、ユーザ情報 を更新するミドルウェアを追加することである.でもまた問題が...このプロジェクトは単一ページアプリケーションであり、すべての機能は非同期要求である.あるボタンをクリックすると、そのボタンに関する内容のみが更新され、他の内容は は更新されないという意味です.は混乱をもたらしやすい.例えばaアカウントの下にbアカウントの情報が表示されると、ユーザー を誤導する.はまた解決策を考えなければならない.aページを操作する時、cookieとstoreのtokenが一致しないことを発見しない限り、すべてのインタフェース情報(現実的ではなく、コード習慣に合わない)を更新する.そして、すべてが更新されれば、ページを更新することと変わらない. で、ページが強制的に更新されます.それは、aページの操作時に を強制的にリフレッシュすることに関する.当時、aページの強制リフレッシュを操作していると感じていたが、ユーザー体験があまりよくなく、未登録ページ にジャンプすることを考慮できるかどうか.
シナリオ4:クッキーの継続
未登録ページにジャンプすると、解決策は、ミドルウェアを追加すると、どのユーザーの行為も、まずミドルウェアを通過し、クッキーとstoreのtokenが一致しているかどうかを判断し、一致しない場合は未登録ページにジャンプします.
先ほど述べたように、同じブラウザで2つのアカウントにログインする問題について、私が理解している同じブラウザ、tokenは異なり、ジャンプするのは正常です.
ただし、同じブラウザで同じアカウントを複数回ログインし、ユーザー名が同じでtokenが異なる.ログインからも飛び出します.もちろん、この場所はユーザー名が一致し、tokenが一致しないと判断し、ログインを終了するように変更することもできます.ここで私が使っている前者.
複数のサーバにフロントエンドコードを配備できることを実現する.
システムせっけい
フロントエンドnodeバックエンド(java)
Nodeレイヤは、(1)サービス側レンダリング、(2)restApiインタフェース処理
テクノロジーアーキテクチャ
react + redux + node + express
改変前の検証ロジック
tokenチェックの採用
バックエンド(java側)はtokenとユーザ情報をdata形式でフロントエンド(node層)に送り、フロントエンド(node層)はsessionに保存され、restApiインタフェースではsessionからこのtokenを取得してreq.headerに保存し、sessionからユーザ名、企業であるかどうかなどのフィールドを特定の必要なインタフェースに置くユーザ情報はセッションに保存されます.セッションはexpress-session、すなわちnodeサーバに保存されます
解決策(passに落とされた)
シリアル番号の問題がある場合、sessionのnodeレイヤでのキャッシュによる可能性が高いと推測されます.
今、この需要を2回します.前回のバージョンを再オンラインにしますか、それとも考えを変えますか.ドキドキ・・・
(PS:一番怖いのは需要が難しすぎて開発できないのではなく、まったく再現できない問題で、手がつけられないのです.
質問を出す
やり直す以上、雨露を均一につけ、すべてのユーザーの世話をしなければならない.どうすればいいですか.
複数のサーバを配備し、ユーザー情報をnodeサーバに保存できない.
理由は簡単で、1台のサーバが停止し、オンラインになった場合、ユーザaのログイン情報が停止されたサーバに保存された場合、そのユーザのログインに異常が発生し、例えばログインを終了するなどである.
では、どこに保存すればいいのでしょうか.
シナリオは、Redisなどのデータベースとフロントエンドの2つです.
Redisは捨てられた
Redisは高性能key-valueデータベースその利点の1つは、マルチプロセスで共有でき、バックアップとリカバリメカニズムが完備されていることです.に似合うようです
しかし、ユーザ情報の処理にRedisを使用するだけでは「不器用」すぎるさらにtokenの検証はバックエンド(javaエンド)で維持され、フロントエンドは要求を送信する際にユーザ情報(tokenを含む)を持っているだけで、データベース依存を追加する必要はない.
3と4の2点を統合したので、この案は放棄された.
フロントエンドに保存されたスキーマ
store(実際にはredux-store)に保存するクッキーに保存する.
以下、この2つの案について、この問題を解決する考え方を詳しく紹介します.
シナリオの検討
シナリオ1:store(破棄)
ログインに成功すると、ユーザー情報はstoreに保存されます.各restApiインタフェースは、storeからのユーザ情報を取得する.
1台のサーバで正常に動作する複数のサーバの場合、apiインタフェースごとにnodeレイヤでstoreからユーザ情報を取得できないことが判明し、undefined として印刷される.
これも理解できます.結局storeはフロントエンドであり、node層はサーバ側に属し、単一のサーバは、キャッシュによるものと推測することができる(検証されていない、推測のみ) シナリオ2:storeストレージ方式の継続(廃棄)
次に、フロントエンドのstoreでユーザ情報を取得し、インタフェースに追加することを考慮する.
1つの理由:username、email、iscompanyなどのフィールドのrestApiインタフェースを単独で変更することに関連する.
2つの理由:tokenの生成ルールは、ipを使用します.つまりipは必ず送らなければならないので、各インタフェースはipというパラメータを送信しなければならず、ユーザーの習慣に合わない.機能が実現しても.
特に第2の原因はを排除した.
シナリオ3:クッキー(廃棄)
const cookieAge = 1 * 60 * 60 * 1000;
res.setHeader('Set-Cookie',
[
`TOKEN=${userInfo.token}`,
`NAME=${Number(username)}`,
`EMAIL=${userInfo.email}`,
`ISCOMPANY=${userInfo.company}`,
],
'Secure',
`Max-Age=${cookieAge}`
);
// api
export default function configureStore(preloadedState) {
return createStore(
rootReducer,
preloadedState,
applyMiddleware(thunk, api(httpClient), auth)
)
}
// api.js。 ,
if (Cookies.get('TOKEN')) {
next(UpdateUserInfo({
token: Cookies.get('TOKEN'),
name: Cookies.get('USERNAME'),
email: Cookies.get('EMAIL'),
iscompany: Cookies.get('ISCOMPANY'),
}))
}
UpdateUserInfo action, store
シナリオ4:クッキーの継続
未登録ページにジャンプすると、解決策は、ミドルウェアを追加すると、どのユーザーの行為も、まずミドルウェアを通過し、クッキーとstoreのtokenが一致しているかどうかを判断し、一致しない場合は未登録ページにジャンプします.
先ほど述べたように、同じブラウザで2つのアカウントにログインする問題について、私が理解している同じブラウザ、tokenは異なり、ジャンプするのは正常です.
ただし、同じブラウザで同じアカウントを複数回ログインし、ユーザー名が同じでtokenが異なる.ログインからも飛び出します.もちろん、この場所はユーザー名が一致し、tokenが一致しないと判断し、ログインを終了するように変更することもできます.ここで私が使っている前者.
// updateUser
export default function configureStore(preloadedState) {
return createStore(
rootReducer,
preloadedState,
applyMiddleware(thunk, updateUser(preloadedState), api(httpClient), auth)
)
}
// updateUser.js
import Cookies from 'js-cookie';
import { loginPage } from '../../middlewares/links';
export default function updateUser(preloadedState) {
return () => next => (action) => {
if (preloadedState &&
preloadedState.auth &&
Cookies.get('TOKEN') !== preloadedState.auth.user.token) {
window.location.href = loginPage;
} else {
return next(action);
}
};
}
以上の内容は、いずれも個人的な経験です.不適切またはより良い提案があれば、コメントを歓迎します.