How to add a custom header to requests in the img tag

Posted by goochy808 on Thu, 12 Sep 2019 02:05:32 +0200

This is the requirement that you have a web page where the upload and preview of pictures come from a separate file server and the request for http requires access permissions to be set by adding an Authorization field to the request header.It's good to say that I just add a header with Axios, but previewing is more cumbersome because img is a label image download display that the browser has implemented itself and there's no way to modify it.So the first thing to think about is adding custom header forwarding requests or other solutions through the interface. How do you do this through front-end pages? First of all, it says that some new API s are used here, so if you have older browsers, you can't do that.

Problem analysis: The src attribute of the IMG tag can only set the url, not the header for this request.In this case, the ability to download pictures before displaying img tags in another way is equivalent to dividing the download and display of src attributes into two steps, first calling the interface to get the data, and then displaying the data, that is, the value in src is not a URL address but a data stream.

You can do this by first defining an authSrc attribute through Object.defineProperty to replace the value of the src attribute, then downloading the picture after the dom is loaded in window.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', 'Voucher Information');
            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>

This allows functionality to be achieved, but each time additional scripts are executed, it is not elegant enough to automatically download the display when the Dom is loaded.Can I download the display automatically?

Loading through custom elements

Custom elements that you don't know much about can be referenced here Using custom elements Here's a draft of the 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', 'Voucher Information');
            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>

Use Node for Request Forwarding

Here I am working on the Electron client and get user credential information by means of inter-process communication. If deployed on a server, I should use another method.

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

    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!');
})

Using Nginx

Since it is possible to forward requests, Nginx is natural, but adding header s to Nginx is fixed and cannot be modified. A way to set this value is to request an address to carry token, and then customize a variable.This is a bit nauseous. First, it exposes token. Second, it can easily cause injuries. It accidentally updates token, and if Nginx restarts it will be gone.It can't be done just as a way of thinking, probably like the following.

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;
    }
}

Topics: Javascript Nginx Attribute axios