• 如何给img标签里的请求添加自定义header?


    是这样的需求,有一个web页面,里面图片的上传和预览来自于一个独立的文件服务器,对http的请求需要进行访问权限的设置,就是在请求的header里加一个Authorization的字段。上传好说我用的Axios直接添加一个header就行了,但是预览就比较麻烦了,因为img这个标签图片下载展示是浏览器自己实现的,没有办法去修改。所以首先想到就是通过接口添加自定义header转发请求或者其他通过接口的方案了,那怎么通过前端页面去实现这个功能,首先声明的是这里用了一些新的API,所以如果是一些比较老的浏览器那就没法这么做了。

    问题分析:img标签的src属性只能设置url,不能设置这次请求的header。既然这样,能不能通过别的方式先把图片下载下来然后再给img标签作展示,相当于把src属性的下载和展示分成了两步,先调用接口获取到了数据,然后再把数据给展示出来,也就是src里的值不是一个url地址而是一个数据流。

    可以这样,首先通过Object.defineProperty定义一个authSrc属性用来替换src属性的值,然后在window.onload里等dom加载完以后去再下载图片。

    <!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加载完的时候自动去下载展示,不够优雅。能不能自动去下载展示呢

    通过自定义元素加载

    自定义元素不太了解的可以参考这里Using custom elements,这里还有个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://39.106.118.122/images/image_201909111450326.jpg">
    </body>
    </html>

    利用Node作请求转发

    这里我是在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!');
    })

    电脑刺绣绣花厂 http://www.szhdn.com 广州品牌设计公司https://www.houdianzi.com

    利用Nginx

    既然作请求转发,那Nginx自然也是可以的,但是Nginx里添加header都是固定,没法去修改,想到了一个方式,先请求一个地址携带token,然后自定义一个变量,去设置这个值。这个方式有点恶心,一来是把token暴露了出来,二来是容易造成误伤,一不小心就把token更新了,而且假如Nginx重启了这时候token也没了。只作为一个思路拓展了,是不能这么搞的,大概像下面这样。

     
    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;
        }
    }
  • 相关阅读:
    iOS核心动画高级技巧之核心动画(三)
    iOS核心动画高级技巧之图层变换和专用图层(二)
    iOS核心动画高级技巧之CALayer(一)
    Swift高级语法学习总结
    Swift基础语法学习总结
    Swift语法总结补充(一)
    【思图佳预约(一)】在做预约挂号小程序时,text标签出现一截多余的空白?
    【随笔】清除浮动float的几种办法
    ----原生js实现飞机大战小游戏<第二篇>----@半城言沙
    ----原生js实现飞机大战小游戏<第一篇>----@半城言沙
  • 原文地址:https://www.cnblogs.com/xiaonian8/p/13839640.html
Copyright © 2020-2023  润新知