項目二(業務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;width: 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.這次需求改動總結的小經驗:

點擊“添加圖片”的時候,自動往后面添加一個相同的上傳圖片的點擊框,即:

自己寫的代碼總是冗雜繁余,而其他人寫的代碼一看卻是那么的簡潔明了,不得不懷疑自己的能力。而自己想長期快樂的繼續自己的這份工作時,就應該好好的沉淀自己,把自己培養成像同事一樣的大神。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM