インスタント メッセージング アプリケーション (サーバー、管理、クライアントを含む)
導入されオンラインになりました。クライアントと管理端末を体験してください。
デフォルトのロールと権限を勝手に変更しないでください。非常に野蛮な名前を使用しないでください。
@vue/cli を使用して構築された IM サービス クライアントは、UI 部分に Vant を使用します
このプロジェクトは主にクライアントの基本的なアプリケーション (WeChat と同様) をデモするためのもので、登録、ログイン、個人情報の編集、友達の追加、グループへの参加申請、チャットなどの機能を備えています。バックエンド。
誰もが Vue Family Bucket プロジェクトに精通しています (この点では React よりも優れていると思いますが、選択肢はそれほど多くありません)。以下にいくつかの拡張機能を示します。
まず、socket.io-client パッケージを紹介します。名前から、これが socket.io のクライアント部分であることがわかります。使用方法は次のとおりです。
サーバーと情報を送受信したい場合は、まずリンクを確立する必要があります。
import io from 'socket.io-client';
// 首先需要链接上后端的 socket.io,query是链接的参数
this.socket = io('http://127.0.0.1:7001', {
query: {
scene: 'im',
userId: '1'
}
});
// socket.on 就是监听事件,connect就是链接上了服务端
this.socket.on('connect', () => {
console.log('socket连接成功!');
// ....
});
このプロジェクトでリンクが成功した後、メッセージを取得するときにリンクが成功したことを確認するために、セッション リストとメッセージ レコードのリクエストを開始しました。
サーバーに接続したら、非常に簡単に情報を送受信できます。
// 发送消息,message是自己定义的消息体
this.socket.emit('/v1/im/new-message', message);
// 有新消息收到
this.socket.on('/v1/im/new-message', message => {
// 自己进行一系列的处理
});
メッセージの送受信はバックエンドと組み合わせることができます。フロントエンドが独自のメッセージを送信した場合でも、バックエンドからグループ メッセージを受信するまでは表示されません。つまり、リンクが切断されている場合、フロントエンド自体のメッセージは表示されません。送られる。
入力時は[酷]
のような純粋な文字列ですが、表示時も対応するアイコンに置き換える方法が見つかりません。入力ボックスに入力します。もともと上司からこれをやってほしいと頼まれてやってみたのですが、これが大きな落とし穴だったことが分かりました。最近では、私が接触した Weibo の入力ボックスのみが文字列ではなくアイコンを表示しているようで、これも多くの疑問につながります。
ただし、文字列 (WeChat と DingTalk の両方) を使用するのは優れており、ネイティブ機能はすべて使用でき、フロントエンドは扱いやすい (重要な点)
上記のことから、最初にリンクを確立し、IM シナリオと組み合わせることで、socket.io がいかに便利であるかがわかります。
/v1/im/new-message
モバイルアプリでスクロールしてクリックして入力するときによく見られます
Web アプリを開発していると、スクロール可能なリスト ページから次の詳細ページに移動し、リスト ページに戻るときに、スクロール バーの状態を復元するのが難しく、覚えられないという問題がよく発生します。引っ越してきた時の場所。
私はこれまでに多くの方法を試してきました。
上記の解決策はいずれも理想的ではありません
その後、Vue ページのスタック、つまり Vue の仮想 dom を保存する keep-alive を参考に vue-page-stack を開発しましたが、スクロールバーの問題は解決されませんでした。仮想 DOM は各コンポーネントのスクロール状態を記録しないため、復元することはできません。
cube-ui を使用したときに、このコンポーネント ライブラリのスクロール コンテナを使用するとスクロール バーを復元できることがわかり、それが Huang Yi 先生のスクロールが改善された理由であることがわかりました。
bs のソース コードを見ると、bs の内部実装はネイティブ スクロールではなく、いくつかのスクロール情報を記録していることがわかりました。そのうちの最も重要なものは、私が実装した一連のスクロール値である x と y です。変換によるスクロール動作の実装では、仮想 DOM を復元するときに、スクロール情報も復元されます。
最終的には、vue—page-stack + bs でページ スタックの復元を完全に実現できます。
この問題は主にメッセージ レコードなどのクエリで発生します。また、小規模なプログラムでもこの問題が発生することがあります。
ほとんどのスクロール シーンはプルアップ ロードであり、ロードされたコンテンツはスクロール領域の下に表示され、Vue などは新しくロードされたコンテンツのレンダリングを続行します。を押してスクロールを続けます。
ただし、このシナリオでは、特定のセッションでメッセージ レコードを参照するときに、プルダウンしてさらにメッセージを読み込み、表示するにはプルダウンを続けてゆっくりスクロールする必要があります。これは非常に深刻な問題につながります。ドロップダウンの読み込み後に表示されるコンテンツは、スクロール領域の上にあります。何も処理が行われない場合、スクロール距離が設定されていないため、読み込み後に新しく読み込まれたコンテンツの先頭に直接ジャンプします。変更されたため、目標と矛盾する問題が発生します。
新しく追加したメッセージの合計の長さを計算してロールバックするなどの方法も考えましたが、メッセージの種類と高さが一致しないため、計算に誤差が生じます。
私が考えた最終的な解決策は次のとおりです。
上記 2 つの問題は下の図に反映されており、次のように効果は OK です。
サーバーの帯域幅が弱すぎるため、できる限り CDN を使用し、サーバーへの負担を大幅に軽減するいくつかの拡張機能を使用したいと考えています。コンテンツのこの部分は Webpack 部分に属します。
// index.html
<script src="https://api.map.baidu.com/getscript?v=3.0&ak=ZHjk59sSOpM1eNWgNWyj9zpyAFTHdL5z"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue-router.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuex.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/vant.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/browser/index.js"></script>
// vue.config.js
externals: {
BMap: 'BMap',
vue: 'Vue',
'vue-router': 'VueRouter',
vuex: 'Vuex',
vant: 'vant',
xgplayer: 'Player'
}
これにより、SameSite が原因で https が安全ではないことが示されましたが、他に方法はありませんでした。
フロントエンドのリソースは、リバース プロキシとして機能する nginx によって管理されます。index.html はフロントエンドにキャッシュされず、1 か月間 gzip 圧縮されます。 api、/public、および /socket .io をサーバーに転送する必要があります。私のサーバーは http://127.0.0.1:7001 で実行されており、WebSocket にアップグレードすることができます。
https 証明書は、https://freessl.cn/ で無料で適用され、nginx で構成された証明書です。
server {
listen 80;
server_name im-client.hezf.online;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
root /data/static/im-client;
index index.html;
try_files $uri $uri/ /index.html;
}
location ~* .(html)$ {
root /data/static/im-client;
access_log off;
add_header Cache-Control no-store;
}
location /static {
access_log off;
root /data/static/im-client;
gzip on;
gzip_buffers 32 8K;
gzip_comp_level 6;
gzip_min_length 100;
gzip_types application/javascript text/css text/xml;
gzip_disable "MSIE [1-6]."; #配置禁用gzip条件,支持正则。此处表示ie6及以下不启用gzip(因为ie低版本不支持)
gzip_vary on;
add_header Cache-Control max-age=2592000;
}
location /api {
proxy_pass http://127.0.0.1:7001;
proxy_connect_timeout 3;
proxy_send_timeout 30;
proxy_read_timeout 30;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto http;
proxy_set_header X-NginX-Proxy true;
client_max_body_size 100m;
}
location /public {
proxy_pass http://127.0.0.1:7001;
proxy_connect_timeout 3;
proxy_send_timeout 30;
proxy_read_timeout 30;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 100m;
}
location /socket.io {
proxy_pass http://127.0.0.1:7001;
proxy_connect_timeout 3;
proxy_send_timeout 30;
proxy_read_timeout 30;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 100m;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
server {
listen 443 ssl;
server_name im-client.hezf.online;
ssl_certificate /etc/nginx/conf.d/hezf-online/im-client.hezf.online_chain.crt;
ssl_certificate_key /etc/nginx/conf.d/hezf-online/im-client.hezf.online_key.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #按照这个协议配置
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4:!DH:!DHE;
ssl_prefer_server_ciphers on;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
location / {
root /data/static/im-client;
index index.html;
try_files $uri $uri/ /index.html;
}
location ~* .(html)$ {
root /data/static/im-client;
access_log off;
add_header Cache-Control no-store;
}
location /static {
access_log off;
root /data/static/im-client;
gzip on;
gzip_buffers 32 8K;
gzip_comp_level 6;
gzip_min_length 100;
gzip_types application/javascript text/css text/xml;
gzip_disable "MSIE [1-6]."; #配置禁用gzip条件,支持正则。此处表示ie6及以下不启用gzip(因为ie低版本不支持)
gzip_vary on;
add_header Cache-Control max-age=2592000;
}
location /api {
proxy_pass http://127.0.0.1:7001;
proxy_connect_timeout 3;
proxy_send_timeout 30;
proxy_read_timeout 30;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-NginX-Proxy true;
proxy_redirect off;
client_max_body_size 100m;
}
location /public {
proxy_pass http://127.0.0.1:7001;
proxy_connect_timeout 3;
proxy_send_timeout 30;
proxy_read_timeout 30;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 100m;
}
location /socket.io {
proxy_pass http://127.0.0.1:7001;
proxy_connect_timeout 3;
proxy_send_timeout 30;
proxy_read_timeout 30;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 100m;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}