img タグのリクエストにカスタムヘッダーを追加する方法

 

        これが要件です。独立したファイル サーバーから画像のアップロードとプレビューを行う Web ページがあります。http のリクエストでは、アクセス権を設定する必要があります。これは、リクエストのヘッダーに Authorization フィールドを追加することです。アップロードの場合は、私が使用しているAxiosに直接ヘッダーを追加するだけで済みますが、プレビューの場合はさらに面倒です。imgラベル画像のダウンロードと表示はブラウザ自体で実装されており、変更する方法がないためです。したがって、最初に考えられるのは、インターフェイスを介してカスタム ヘッダー転送リクエストを追加するか、インターフェイスを介して他のソリューションを追加することです。次に、フロントエンド ページを通じてこの機能を実現する方法を考えます。最初のステートメントは、ここではいくつかの新しい API が使用されているということです。古いブラウジングです。デバイスではそれができません。

        問題分析:imgタグの src 属性は URL のみを設定でき、このリクエストのヘッダーは設定できません。この場合、最初に画像をダウンロードしてから、他の方法で img タグに表示できますか。これは、src 属性のダウンロードと表示を 2 つのステップに分割し、最初にインターフェイスを呼び出してデータを取得し、次にデータを表示します。つまり、src の値は URL アドレスではなく、データ ストリームです。

        これは次のようになります。最初に Object.defineProperty を通じて authSrc 属性を定義して src 属性の値を置き換え、次に dom が wi​​ndow.onload にロードされた後にピクチャをダウンロードします。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Proxy Image</title>
    <script>
        Object.defineProperty(Image.prototype, 'authsrc', {
            writable : true,
            enumerable : true,
            configurable : true
        })
        window.onload = () => {
            let img = document.getElementById('img');
            let url = img.getAttribute('authsrc');
            let request = new XMLHttpRequest();
            request.responseType = 'blob';
            request.open('get', url, true);
            request.setRequestHeader('Authorization', '凭证信息');
            request.onreadystatechange = e => {
                if (request.readyState == XMLHttpRequest.DONE && request.status == 200) {
                    img.src = URL.createObjectURL(request.response);
                    img.onload = () => {
                        URL.revokeObjectURL(img.src);
                    }
                }
            };
            request.send(null);
        }
   </script>
</head>
<body>
<img width="100" height="100" id="img" authsrc="http://threex.top/images/image_201909111450326.jpg">
</body>
</html>

        このようにして機能は実現できますが、追加スクリプトを毎回実行する必要があり、Domロード時に自動的にダウンロードして表示することができず、エレガントとは言えません。自動的にダウンロードして表示することはできますか?

       カスタム要素経由でロードする

        カスタム要素についてあまり詳しくない場合は、「ここでカスタム要素の使用」を参照してください。また、w3c ドラフトのAutonomous-custom-elementもあります。 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Proxy Image</title>
    <script>
        let requestImage = function (url, element) {
            let request = new XMLHttpRequest();
            request.responseType = 'blob';
            request.open('get', url, true);
            request.setRequestHeader('Authorization', '凭证信息');
            request.onreadystatechange = e => {
                if (request.readyState == XMLHttpRequest.DONE && request.status == 200) {
                    element.src = URL.createObjectURL(request.response);
                    element.onload = () => {
                        URL.revokeObjectURL(element.src);
                    }
                }
            };
            request.send(null);
        }

        class AuthImg extends HTMLImageElement {
            constructor() {
                super();
                this._lastUrl = '';
            }

            static get observedAttributes() {
                return ['authSrc'];
            }

            connectedCallback() {
                let url = this.getAttribute('authSrc');
                if (url !== this._lastUrl) {
                    this._lastUrl = url;
                    requestImage(url, this);
                }
                console.log('connectedCallback() is called.');
            }
        }

        window.customElements.define('auth-img', AuthImg, {extends: 'img'});
    </script>
</head>
<body>
<img width="100" height="100" is="auth-img"
     authSrc="http://threex.top/images/image_201909111450326.jpg">
</body>
</html>

        リクエストの転送にノードを使用する

        ここでは Electron クライアント上で使用しており、ユーザーの認証情報はプロセス間通信で取得していますが、サーバー上にデプロイする場合は他の方法を使用する必要があります。

let app = http.createServer((request, response) => {
    let config = {
        host: 'xxx.com',
        method: 'GET',
        path: request.url,
        headers: {
            Authorization: '用户凭证'
        }
    };

    let proxyRequest = http.request(config, proxyResponse => {
        proxyResponse.on('data', data => {
            response.write(data, 'image/jpg');
        });
        proxyResponse.on('end', () => {
            response.end();
        });
        response.writeHead(proxyResponse.statusCode, proxyResponse.headers);
    })

    request.on('data', data => {
        proxyRequest.write(data, 'image/jpg');
    })
    request.on('end', () => {
        proxyRequest.end();
    })
});

app.listen(port, () => {
    console.log('has start proxy server!');
})

        Nginxを使用する 

        リクエストが転送されるので当然Nginxも可能ですが、Nginxで追加されるヘッダーは固定で変更できないため、まずトークンを運ぶアドレスをリクエストし、その値を設定する変数をカスタマイズする方法を考えました。この方法は少し気持ち悪いもので、第一にトークンが公開されること、第二に不慮の怪我を引き起こしやすく、トークンが誤って更新され、Nginx を再起動するとトークンが消えてしまいます。アイデアとして膨らませただけで、こんなことはできない、おおよそ次のような感じです。

server {

    ...
    
    set $AUTH_TOKEN "";
    
    location /token/([0-9a-z])$ {
        set $AUTH_TOKEN $1;
        return 200;
    }
    
    location /image {
        proxy_pass  http://xxx.com;
        proxy_set_header Authorization $AUTH_TOKEN;
    }
}

おすすめ

転載: blog.csdn.net/m0_67063430/article/details/129023130