如何給img標籤裏的請求添加自定義header

如何給img標籤裏的請求的添加自定義header

是這樣的需求,有一個web頁面,裏面圖片的上傳和預覽來自於一個獨立的文件服務器,對http的請求須要進行訪問權限的設置,就是在請求的header里加一個Authorization的字段。上傳好說我用的Axios直接添加一個header就好了,可是預覽就比較麻煩了,由於img這個標籤圖片下載展現是瀏覽器本身實現的,沒有辦法去修改。因此首先想到就是經過接口添加自定義header轉發請求或者其餘經過接口的方案了,那怎麼經過前端頁面去實現這個功能,首先聲明的是這裏用了一些新的API,因此若是是一些比較老的瀏覽器那就無法這麼作了。html

問題分析:img標籤的src屬性只能設置url,不能設置此次請求的header。既然這樣,能不能經過別的方式先把圖片下載下來而後再給img標籤做展現,至關於把src屬性的下載和展現分紅了兩步,先調用接口獲取到了數據,而後再把數據給展現出來,也就是src裏的值不是一個url地址而是一個數據流。前端

能夠這樣,首先經過Object.defineProperty定義一個authSrc屬性用來替換src屬性的值,而後在window.onload裏等dom加載完之後去再下載圖片。node

<!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://39.106.118.122/images/image_201909111450326.jpg">
</body>
</html>

這樣雖然能夠實現功能,可是每次還須要執行額外的腳本,不能在Dom加載完的時候自動去下載展現,不夠優雅。能不能自動去下載展現呢ios

經過自定義元素加載

自定義元素不太瞭解的能夠參考這裏Using custom elements,這裏還有個w3c的草案autonomous-custom-elementgit

<!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://39.106.118.122/images/image_201909111450326.jpg">
</body>
</html>

利用Node做請求轉發

這裏我是在Electron客戶端用的,是經過進程間通訊的方式獲取到了用戶憑證信息,若是是部署在服務器上的話,應該使用其餘方式。github

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裏添加header都是固定,無法去修改,想到了一個方式,先請求一個地址攜帶token,而後自定義一個變量,去設置這個值。這個方式有點噁心,一來是把token暴露了出來,二來是容易形成誤傷,一不當心就把token更新了,並且假如Nginx重啓了這時候token也沒了。只做爲一個思路拓展了,是不能這麼搞的,大概像下面這樣。web

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;
    }
}
相關文章
相關標籤/搜索