レポーター:私は2018年6月に卒業してから、2年目から3年目でプログラマーの転機を迎えようとしています。
コードを書く前に、私はいつも頭を作っていて、だんだんと書いてきましたが、実際の技術的な進歩はめったに見られません。今、半減期に入ったので、基本的なビジネス要件を書き留めることができますが、実際の出会いいくつかの奇妙な問題について、私は無力感を深く感じています。
表示されるシーンは次のとおりです。
1.会社のビジネスニーズ、統合ユーザー、シングルサインオン、ログアウト方法を実現したい場合は、casフレームワークを選択します。
2.奇妙なバグ、元のプロジェクトはcasクライアントを時々統合し、例外はグローバル例外によってインターセプトされず、スタック情報がページに直接印刷されます。
シナリオ1の場合:
同社の元の古いプロジェクトはcasに接続され、プロジェクトのcasクライアントに統合されていますが、シングルポイントからログアウトできないことがよくあります。使用される方法は、バグのシーンを繰り返し、それを見つけて定期的に生成されるかどうかを確認することです。ご存じのとおり、マシンは偽物ではありません。何度もテストと再現を繰り返すと、問題は着実に再現されます。 。システムAとシステムBユーザーがシステムAのログアウトインターフェイスを呼び出す場合、システムBはログアウトする必要があります。ユーザーがシステムBのシングルポイントログアウトインターフェイスを呼び出す場合、システムAは一定の確率でログアウトします。
casプロジェクトは、以前は会社の同僚が作成したものでしたが、同僚が仕事を辞めてプロジェクトを引き継いだため、退屈にしか見ることができません。繰り返し発生するシナリオの問題を考慮して、配備シナリオを尋ねましたが、推測はクラスターの問題が原因でした。プロジェクトAはクラスターにデプロイされ、javaには2つのマシンがあり、プロジェクトBは1つのマシンです。最初の推測では、プロジェクトAがログアウトするとプロジェクトBに通知され、単一のマシンに通知する必要があると考えられます。プロジェクトBがプロジェクトAに不定期に通知する場合。(この説明を簡単に理解するために、実際の通知プロセスは、プロジェクトA-> cas->プロジェクトBまたはプロジェクトB-> cas->プロジェクトAです)。
インターネットで解決策を検索したところ、3つの解決策が見つかりました。(1)クラスタープロジェクトAの構成をIPハッシュに変更します。実際のオンライン方法はIPポーリングです(2)通知にはIPブロードキャストが使用されますマシンによって展開されたIPを形成し、ブロードキャストします。マシンが正常に実行されなかった場合は、次のマシンに転送されます。(3)セッションストレージを書き換えます。
上記が解決策ですが、この問題がcasで発生する理由についての詳細な説明はありません。ログインとして使用されたロゴはredisではなくメモリに保存されるため、個人的な推測ですが、プロジェクトを引き継ぐときに、同僚はロゴがredisに保存され、redisライブラリで見られる状況が実際に保存されることを明確に伝えました。失敗した場合、redisのこのキーにも値はありませんが、ログアウトが失敗した場合でも、redisのこの値は存在します。インターネットでブログを読むときの解決策は、-cas自体がクラスタリングをサポートしていないという記事を見つけたことです。突然、次のように、ソースIDにセッションIDを格納するコードを見たことがわかりました。
public finalクラスHashMapBackedSessionMappingStorageはSessionMappingStorageを実装します{ private final Map <String、HttpSession> MANAGED_SESSIONS = new HashMap(); private final Map <String、String> ID_TO_SESSION_KEY_MAPPING = new HashMap(); プライベート最終ロガーロガー= LoggerFactory.getLogger(this.getClass()); public HashMapBackedSessionMappingStorage(){ } public synchronized void addSessionById(String mappingId、HttpSession session){ this.ID_TO_SESSION_KEY_MAPPING.put(session.getId()、mappingId); this.MANAGED_SESSIONS.put(mappingId、session); } }
SessionMappingStorageの実装クラスが実際にセッションの内容とセッションを格納し、マッピング関係のマッピングがメモリに書き込まれているマップに格納されていることがわかります。その後、この問題を解決することは難しくありません。このメソッドの実装を書き直してフィルターに追加します。両方の関係はredisを使用して保存されます。終わりに、花を振りかけます。インターネット上の人々も放送方法を使用していますが、これも非常に優れていますが、比較的言えば、実装コストは比較的高く、問題の根本的な解決策ではありません。ipハッシュ方式を使用してテストサーバー上にクラスターを構築することも可能ですが、リーダーはipハッシュエネネンのオンラインでの使用を許可しないため、これは行き止まりです。
要約すると、ソースコードはそれほどひどいものではありません。アイデアを見つけて問題に焦点を当て、問題を確認すると、解決策が出てきます。
シナリオ2の場合:
Javaプロジェクトを作成するときは、通常、プロジェクト作成の最初にグローバル例外処理クラスを作成し、システム内のコードエラーやその他の問題によって発生した例外を固定形式のコードメッセージにカプセル化して、フロントページに返します。プロジェクトがスムーズに実行される前に、casクライアントの導入後、シングルサインアウトの問題が解決されると、インターフェイスアクセス500、スタック情報が直接フォアグラウンドで出力されます。
それでも最初に問題を特定する必要があります。例外のタイプに関連していると思われます。ログインインターフェースで、チケットの検証に合格しませんでした。ログインに失敗した場合、TicketValidationExceptionとして出力されます。redisサーバーがハングしたため、RedisConnectionFailureExceptionも発生しました。ローカルでシミュレーション
@GetMapping( "/ test") public void test()throws Exception { throw new TicketValidationException( "ticket validation exception"); //新しいRedisConnectionFailureException( "redis接続例外"); }をスローします
どちらの例外もインターセプトして、正常に返すことができます。これまでのところ、この方法は機能せず、例外の種類に理由がないため、例外の場所を見つけ、次のコードを見つけました。
public void doFilter(ServletRequest servletRequest、ServletResponse servletResponse、FilterChain filterChain)はIOException、ServletExceptionをスローします{ HttpServletRequest request =(HttpServletRequest)servletRequest; HttpServletResponse response =(HttpServletResponse)servletResponse; if(!this.handlerInitialized.getAndSet(true)){ HANDLER.init(); } if(HANDLER.process(request、response)){ filterChain.doFilter(servletRequest、servletResponse); //発生生异常的代码行 } }
さて、それは簡単ではありません。私はあなたを捕まえようとします。まず、TicketValidationExceptionをキャッチして、ライン上のチケットの失敗をシミュレートします。その後、ショックを受けました。それでも、フロントページにスタック情報を印刷してから、金曜日にもう仕事を降りる時間です、この質問は保留されています。家に戻った後も、この問題についてまだ考えていましたが、コンピューターの電源を入れてRedisConnectionFailureExceptionを試しましたが、返されたページはまだ正しくありませんでした。ここで応答を書き換えた後、正常に戻ります。応答を書き換える方法は次のとおりです。
public static void outResponse(HttpServletResponse response、Object object){ response.setCharacterEncoding( "UTF-8"); response.setContentType( "application / json; charset = utf-8"); PrintWriter out = null; { out = response.getWriter();を試してください。 out.append(JSONObject.toJSONString(object)); } catch(IOException e){ e.printStackTrace(); }最後に{ if(out!= null){ out.close(); } } }
redis接続が異常に解決されました。チケット検証の失敗についてはどうですか?redis接続例外をキャッチした後、Exception大きな例外クラスをキャッチし、応答を出力して、インターセプトできることを確認します。チケットの検証が失敗した場合、なぜこの例外をインターセプトできないのか、ソースコードの実装を見てください。
catch(TicketValidationException var8){ this.logger.debug(var8.getMessage()、var8); this.onFailedValidation(request、response); if(this.exceptionOnValidationFailure){ 新しいServletException(var8);をスローします。 } response.sendError(403、var8.getMessage()); 戻る;
ここで投げたのは、実際にはServletException変更コードです。チケット例外が発生したときにキャプチャされたコンテンツは、ServletExceptionをキャプチャする必要があります。
ソースコードを聞くと、まるで大きな虎のように見えましたが、真剣に勉強してみると、子猫のように優しくて親切でした。ボスが書いたコードが曖昧で理解しづらいことも否定されませんが、結局のところ、それは人が書いたものです。心をこめて読んでもかまわない限り、間違いなく何かが得られます。流行が早く終わり、皆が2020年にうまく治療されることを願っています。