• 项目二(业务GO)——跨域上传图片(请求接口)


    之前,就听过“跨域上传”图片的问题,只是疏于研究,也就一再搁置,直至今天再次遇见这个不能避免的“坑”,才不得不思考一下,怎么“跨域上传”图片或者文件?

    问题来源:

    何为“跨域”? ——就是给你一个接口,外面暴露的url(并非是自己项目中的url),然后你发post()请求,请求给你的接口,请求成功,接口就会返回给你想要的结果。

    实际情况:

    我们公司自己做的项目一般都是使用nodejs的thinkjs框架(ThinkJS 是一款使用 ES6/7 特性全新开发的 Node.js MVC 框架,使用 ES7 中 async/await,或者 ES6 中的 */yield 特性彻底解决了 Node.js 中异步嵌套的问题。)之前我们的上传图片都是显示在自己项目本地,而这次的需求却加上了请求另一个人的接口地址,然后正常上传图片。

    页面HTML主要代码:

    ...
    <label style="fmargin-top: 10px; 100px" ></label>
        <div id="addImg">
            <span class="addImglist"></span>
            <img id="addPic" style="float: left;margin-top: 20px;margin-left: 20px" width="150px" height="100" src="/static/admin/img/addimg.jpg" onclick="addImg()">
        </div>
    <input type="file" name="uploadFile" id="fileupload_input" style="display: none"/>
    
    
    <div class="temp"  style="float: left;margin-top: 20px;margin-left: 20px">
       <img src="" class="showImg" ondblclick="canceImg(this)" width="150px" height="100"/>
       <input type="hidden" class="imgs" name="imgs"/>
    </div>
    ...
    <script>
     function addImg() {
            uploadimg('dynamic');
        }
    
    
     function uploadimg(type) {//这里的图片上传分为两种形式:动态以及用户头像
            var url='';
            if(type=='dynamic'){
                url="/tools/uploadutils/uploadtonet?type=dynamic&t=" + new Date().getTime();//文件上传地址 请求接口地址
            }else{
                url="/article/article/upload?type=portrait&t=" + new Date().getTime();//文件上传地址
            }
            jQuery('#fileupload_input').click().fileupload({
                dataType: 'json',
                url: url,
                done: function (e, result) {
                    if (result.result.errno==0) {
                        var data=result.result.data;
                        if(type=='dynamic'){
                            jQuery(".temp:first").clone().appendTo('#addImg .addImglist');
                            if(jQuery(".temp").length>=10){
                                jQuery("#addPic").hide();
                            }
                            jQuery('#addImg .showImg:last').attr("src",data.path);
                            jQuery('#addImg .imgs:last').val(data.savePath);
                        }else{
                            jQuery('#portrait').attr("src",imgsite+"/static"+data.path);
                            jQuery('#img').val(data.savePath)
                        }
                    } else {
                        jQuery.messager.alert('提示', "上传失败");
                    }
                }
            });
        }
    
      function canceImg(me) {
            jQuery(me).parent().remove();
            if(jQuery(".temp").length<10){   //只能上传九张图
                jQuery("#addPic").show();
            }
        }
    </script>

    后台项目中的js代码:

    uploadutils.js(文件路径:/tools/uploadutils/的uploadtonet方法):

    /**
     * Created by *** on 2016/11/10
     */
    'use strict';
    
    import Base from '../base.js';
    import imgutil from '../../../common/util/imgutil';
    import fs from 'fs';
    import request from 'request';
    
    
    
    export default class extends Base {
        /**
         * 上传图片给前台接口(c#程序)
         * @returns {Promise|*|void|PreventPromise}
         */
        async uploadtonetAction() {
            let type = this.get("type");
            if (!think.isEmpty(this.file('uploadFile'))) {
                let savePath = "";//保存在数据库的路径
                let file = think.extend({}, this.file('uploadFile'));
                let fPath = file.path;
                let suffix = fPath.substr(fPath.lastIndexOf(".") + 1);
                if (suffix == "jpg" || suffix == "png" || suffix == "jpeg") {
                    let apiBaseUrl = this.config("apiUrl");
                    let reqUrl = apiBaseUrl + "/upload.ashx"; //c#接口请求地址
                    let fileObj = imgutil.getCSharpImageUrl(this.param("type"), suffix);
                    let path = fileObj.path + fileObj.fileName;
                    let dbUri = "/" + path;  //数据库保存的路径
                    let req = think.promisify(request.post);
                    let options = {
                        url: reqUrl,
                        method: "post",
                        formData: {
                            file: fs.createReadStream(fPath),
                            path: path
                        }
                    };
                    let res = await req(options);
                    let result = JSON.parse(res.body);
                    let imgUrl = this.config("apiImgsite") + dbUri; //回显的路径
                    if (result.status == 1) {//上传成功
                        savePath = result.data.join(',');
                        return this.success({
                            path: imgUrl,
                            savePath: savePath
                        });
                    } else {
                        return this.fail();
                    }
                } else {
                    return this.fail("上传图片格式有误,请重新上传!");
                }
            }
        }
    
        //跨域请求的方法
        call = async function (url, fPath, path) {
            let req = think.promisify(request.post);
            let reqObj = {
                url: url,
                method: "post",
                formData: {
                    file: fs.createReadStream(fPath),
                    path: path
                }
            };
            return req(reqObj);
        };
    }

    主要的问题出在哪里呢???其实主要知识点就是在下:

       这段代码是老大给的,为此还被骂了一顿(这段代码很难理解吗?其实也不然,有时候就是觉得自己的脑子在代码运行方面实在不怎么灵光!明明自己知道的东西,因为粗心或者不自信总是犯错,导致一些不可挽回的“形象破坏”):

        XMLHttpRequest Level 2添加了一个新的接口FormData.利用FormData对象,我们可以通过JavaScript用一些键值对来模拟一系列表单控件,我们还可以使用XMLHttpRequest的send()方法来异步的提交这个"表单".比起普通的ajax,使用FormData的最大优点就是我们可以异步上传一个二进制文件。(https://developer.mozilla.org/zh-CN/docs/Web/API/FormData)

    在网上找到了一个C#实现http协议GET、POST请求 ,觉得挺好的    http://blog.chinaunix.net/uid-7552018-id-173395.html

    const options = {
      method: 'POST', 
      uri: testData.url + `uploadprofilephoto`,
      formData: {
        image: fs.createReadStream('/home/rje/photo.jpg')
      }
    };
    const json: IResponse<string> = await request(options);

    uri:就是要请求的图片上传地址;

    formData:模拟表单提交,接口需要两个参数,一个文件路径,一个文件名,以键值对的形式传给它,最终便会返回给你想要的东西了。

    只是在此项目中,使用await request(option)得不到接口返回的结果,于是只能使用thinkjs自带的 think.promisify()   —— think.promisify将一个异步函数自动改造,返回一个promise对象以供调用。

      

    1.npm中request-promise模块(https://www.npmjs.com/package/request-promise),有具体的用法;

    2.这次需求改动总结的小经验:

    点击“添加图片”的时候,自动往后面添加一个相同的上传图片的点击框,即:

    自己写的代码总是冗杂繁余,而其他人写的代码一看却是那么的简洁明了,不得不怀疑自己的能力。而自己想长期快乐的继续自己的这份工作时,就应该好好的沉淀自己,把自己培养成像同事一样的大神。

  • 相关阅读:
    用户验证之自定义身份验证
    再谈CLR:查看程序集的依赖关系
    关于私钥加密、公钥加密、签名在生活中的场景
    MOSS 2010服务器对象模型(Object Model)
    用户身份验证之Windows验证
    由object不能比较引发的问题
    再谈CLR: .NET 4.0新功能:Mscoree.dll + Mscoreei.dll=更少的Reboot (上)
    再谈CLR:事件定义
    WPF:如何为程序添加splashScreen?
    通过反射得到类型的所有成员
  • 原文地址:https://www.cnblogs.com/zhengyeye/p/6044347.html
Copyright © 2020-2023  润新知