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

问题来源:

何为“跨域”? ——就是给你一个接口,外面暴露的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.这次需求改动总结的小经验:

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

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

项目二(业务GO)——跨域上传图片(请求接口)的更多相关文章

  1. vue.js axios实现跨域http请求接口

    跨域post实例,用到了qs组件来避开ajax信使请求,并兼容Android. import axios from 'axios'; import qs from 'qs'; axios.post(' ...

  2. 从壹开始前后端分离【 .NET Core2.0 +Vue2.0 】框架之十二 || 三种跨域方式比较,DTOs(数据传输对象)初探

    更新反馈 1.博友@落幕残情童鞋说到了,Nginx反向代理实现跨域,因为我目前还没有使用到,给忽略了,这次记录下,为下次补充.此坑已填 2.提示:跨域的姊妹篇——<三十三║ ⅖ 种方法实现完美跨 ...

  3. kindeditor4跨域上传图片解决

    项目中正在使用kindeditor, 版本号4.1.10 非常多公司的图片会走CDN,须要单独的一台图片上传服务如:(upload.268xue.com) kindeditor上传图片的简单内部流程: ...

  4. 跨域Ajax请求WebService方法

    一.允许跨域Ajax请求,更改如下配置: 在要调用的WebService上面添加特性标签: 二.以如下返回用户信息的WebService方法为例 三.在另一个网站上通过Ajax访问webService ...

  5. 【笔记】vue-cli 开发环境中跨域连接后台api(vue-resource 跨域post 请求)

    在vue-cli 项目中很多人会用到mock 数据(模拟数据),但是我觉得如果在真实的数据库交互中开发会更有安全感一些,所以查了一下百度很多人推荐的就是: 跨域! 跨域是什么概念?不同的主机名,同主机 ...

  6. ueditor富文本编辑器跨域上传图片解决办法

    在使用百度富文本编辑器上传图片的过程中,如果是有一台单独的图片服务器就需要将上传的图片放到图片服务器,比如在a.com的编辑器中上传图片,图片要保存到img.com,这就涉及到跨域上传图片,而在ued ...

  7. 【HTTP header】【Access-Control-Allow-Credentials】跨域Ajax请求时是否带Cookie的设置

    1. 无关Cookie跨域Ajax请求 客户端 以 Jquery 的 ajax 为例: $.ajax({ url : 'http://remote.domain.com/corsrequest', d ...

  8. 原创:【ajax | axios跨域简单请求+复杂请求】自定义header头Token请求Laravel5后台【亲测可用】

    如标题:我想在ajax的header头增加自定义Token进行跨域api认证并调用,api使用laravel5编写,如何实现? 首先,了解下CORS简单请求和复杂请求.  -- CORS简单请求 -- ...

  9. 跨域Ajax请求时是否带Cookie的设置

    1. 无关Cookie跨域Ajax请求 客户端 以 Jquery 的 ajax 为例: $.ajax({ url : 'http://remote.domain.com/corsrequest', d ...

随机推荐

  1. jq 解析josn字符串

    1. var obj = jQuery.parseJSON("${ruleModel.rules}"); 2. var obj = eval("("+" ...

  2. cxf(3.1.1) 异常Caused by: java.io.FileNotFoundException: class path resource [META-INF/cxf/cxf-extension-soap.xml]

    Caused by: java.io.FileNotFoundException: class path resource [META-INF/cxf/cxf-extension-soap.xml] ...

  3. Entity FrameWork对有外键关联的数据表的添加操作

    前天做了一个MVC Entity FrameWork项目,遇到有外键关联的数据编辑问题.当你编辑的时候,按照正常的逻辑,把每个字段的数据都对号入座了,然后点击保存按钮,本以为会顺理成章的编辑数据,但是 ...

  4. Jenkins TcpSlaveAgentListener Config

    http://wenku.baidu.com/link?url=wDbeRoqh8ERRvBKXsKVi7biWe8e369iZmYTfEFDz0aI1Sj5YjXq_AN1gFjFjiS0yBw0W ...

  5. "未能找到类型或命名空间名称",引用dll的时候出错

    当前项目是.net2.0框架,引用的dll是 .net 4.5框架,引用后编译时报错“未能找到类型或命名空间名称”. 当前项目 右键-->应用程序-->目标框架 改为 .net frame ...

  6. usermod

    环境: [root@vm-xiluhua][/]# cat /etc/redhat-release CentOS Linux release (Core) usermod usage:(本人使用的版本 ...

  7. 新知识:Java 利用itext填写pdf模板并导出(昨天奋战到深夜四点,知道今天两点终于弄懂)

    废话少说,不懂itext干啥用的直接去百度吧. ***************制作模板******************* 1.先用word做出界面 2.再转换成pdf格式 3.用Adobe Acr ...

  8. python之rabbitMQ篇

    一.RabbitMQ安装 RabbitMQ是一个在AMQP基础上完整的,可复用的企业消息系统,它遵循Mozilla Pulic License开源协议. MQ全称为Message Queue,消息队列 ...

  9. android 事件监听

    步骤: 1.获取代表控件对象. 2.定义一个类,实现监听接口. 3.生成监听器对象. 4.为控件绑定监听器对象. XML <LinearLayout xmlns:android="ht ...

  10. 大分享-hibernate,springmvc,easyui简要介绍

    近期公司一直在做项目,主要用到了springMVC,eseayui,hibernate几大框架.近一个月的时间,个人就目前自我知识给予分享. 很多公司使用mybatis产品,综合所述其最大优点是全SQ ...