プロトコルバッファをフロントエンドプロジェクトに適用する孤軍奮闘



1.初期の話題

  • どうしますか.protoファイルのインポートか
  • のインポートか
  • どうしますか.protoファイルを外部に露出しませんか?
  • 自動符号化及び復号化
  • 2.解決


    2-1. 準備完了:必要なライブラリ

    yarn add protobufjs
    終わりだ!

    2-2. .protoファイルインポートホットスポット


    結論から言う.jsファイルインポートに変換します.WebspecやBundlerの設定に面倒に触れる必要はなく、露出せずに同期して呼び出すことができます.
    # .proto 파일들이 ./assets/proto/src 디렉토리에 존재한다고 가정하고,
    # 최종 산출물을 ./assets/proto/proto.js 로 익스포트 하는 npm 스크립트
    
    npx pbjs -t json-module -w commonjs -o ./assets/proto/proto.js ./assets/proto/src/*.proto
    上の小包.jsonのscriptsセクションに挿入し、適切な時間に実行します.私の場合、dev(start)と構築の前に実行させます.
    計算された結果ゲートは一般的なモジュール形式でインポートされます.参考までにProtobuf.jsという名前のProtoRootのオブジェクトを返します.
    import ProtoRoot from '@/assets/proto/proto';

    2-3. コーディングとデコード


    protobuf.js公式サイトでドキュメントページをよく読んでも、最終的には長い挿入が行われました.次に、符号化および復号コードを示します.
    export function encode (data, type) {
        const message = ProtoRoot.lookup(type);
        const buffer = message.encode(message.fromObject(data)).finish();
    
        return btoa(String.fromCharCode.apply(null, buffer));
    }
    
    export function decode (data, type) {
        const message = ProtoRoot.lookup(type);
        const buffer = Uint8Array.from(atob(data), c => c.charCodeAt(0));
    
        return message.decode(buffer);
    }
    では、通信モジュールに接続し、応答をブロックし、コンテンツを符号化復号するために要求するモジュールが作成されました.これはとても意味のあることです.今は何も起こらないと思っていたのですが...

    3. Type: google.protobuf.


    3-1. 今は何も怖くない。


    ついに伏兵が現れた.バックエンドにprotobufferが導入されると、falsey値を符号化すると、プロジェクト自体が消えるというホットな問題がある.そのため、基本タイプではなくグーグルが提供するライブラリをfalsey値を含む可能性のあるプロジェクトに適用し、適用後の正常な通信からエラーが発生し始めた.
    JSONデータの内部を調べたら、すぐに原因が分かりました.データの構造自体が変化します.まず混乱を防ぐため、上記のタイプを「Googleタイプ」と呼びます.
    Googleタイプで指定されたデータをWeb上で復号すると、このような形式になります.
    // 서버에서 내려준 값
    {
      foo: 'bar',
    }
    
    // 실제로 프론트에서 받은 값
    {
      foo: { value: 'bar' },
    }
    既存のデータと形式が変化したため、エラーが発生しました.また、iOSやAndroidでは、グーグルタイプを適用すると、これらの空の値の項目は正常に下がり始めますが、Web上では変わらず、Webフロントから見れば、これこそ悪いです(仕事でしょう、グーグル...それはあなたたちが管理しているライブラリではありませんか!)
    まず、アプリ部分で受け取れると聞いたので、ネットフロント部分で不便を引き受けることにしました.まず,{value}として低下した値は自己催眠し,低下しない値は復号時に設定されたデフォルト値を強制的に注入する.
    export function decode (data, type) {
        const message = ProtoRoot.lookup(type);
        const buffer = Uint8Array.from(atob(data), c => c.charCodeAt(0));
        const decoded = message.decode(buffer);
    
        return message.toObject(decoded, { defaults: true });
    }

    3-2. どうやってコードする?


    問題は符号化です.JSONデータを作成する場合は、Googleタイプに対応する値を{value}形式で包んでエンコードする必要があります.エラーが発生するたびに、手で操作してもできないことはありませんが、少しスマートではないような気がします.長いプロトコルバッファリストを見るたびにタイプを確認するのは面倒です.
    元の通りにしましょう.コードするときはそれなりの形でグループ化しましょう.
    import fp from 'lodash/fp';
    //  우리의 친구 Lodash를 사용했지만 로직만 이해한다면 그냥 Javascript 로 짜도 좋고, 다른 라이브러리를 써도 좋다.
    
    
    const parseMessage = (data, type) => ({
        message: ProtoRoot.lookup(type),
        parsed: parseData(data, ProtoRoot.lookup(type).fields),
    });
    
    const parseData = (data, fields) => {
        const convert = (key, value) => (
            typeof value === 'object' && key !== 'value'
                ? parseMessage(value, fields[key].type).parsed
                : value
        );
    
        return fp.flow(
            fp.toPairs,
            fp.reduce((acc, [key, value]) => { 
                acc[key] = convert(key, value);
                return acc;
            }, {}),
            fp.toPairs,
            fp.reduce((acc, [key, value]) => {
                acc[key] = /^google\.protobuf\./.test(fields[key].type)
                    ? { value: value }
                    : value;
                return acc;
            }, {}),
        )({...data});
    };
    
    export function encode (data, type) {
        const { message, parsed } = parseMessage(data, type);
        const buffer = message.encode(message.fromObject(parsed)).finish();
    
        return btoa(String.fromCharCode.apply(null, buffer));
    };

    [原句]とにかく上手に書けた


    よく書けています.ちなみに、会社が心配していた他社が勝手にAPIデータを盗用した問題も解決されました.△.protoファイルがなければ、復号されたコンテンツを人間が認識できる形式に符号化することはできない.これは暗号化である可能性がある.もちろん、暗号化とは根本的に異なり、当初開発された技術の目的や方向性自体も異なる.
    でもgoogleは.必ずそうしなければなりませんか?本当に、これが一番......?