Editor.md图片跨域问题

问题:

Editor.md 是一款开源的、可嵌入的 Markdown 在线编辑器(组件),基于 CodeMirror、jQuery 和 Marked 构建。

但是,在使用Editor.md的时候配置图片上传时候遇到了一个问题:在图片上传时,出现跨域问题!

Uncaught DOMException: Blocked a frame with origin “http://127.0.0.1:8848” from accessing a cross-origin frame.
at HTMLIFrameElement.uploadIframe.onload (http://127.0.0.1:8848/YLBlog/plugins/image-dialog/image-dialog.js:164:129)

但是,我服务器后台能接收到前端传来的参数

由此证明,图片数据是能传递过来服务器的,但是为什么前端会报跨域问题呢?

首先看一下报错的代码,打开 image-dialog.js:164

uploadIframe.onload = function() {

	loading(false);

	var body = (uploadIframe.contentWindow ? uploadIframe.contentWindow : uploadIframe.contentDocument).document.body;
	var json = (body.innerText) ? body.innerText : ( (body.textContent) ? body.textContent : null);

	json = (typeof JSON.parse !== "undefined") ? JSON.parse(json) : eval("(" + json + ")");

	if(!settings.crossDomainUpload)
	{
	if (json.success === 1)
	{
	dialog.find("[data-url]").val(json.url);
	}
	else
	{
	alert(json.message);
	}
	}

	return false;
};

164行的代码是

var body = (uploadIframe.contentWindow ? uploadIframe.contentWindow : uploadIframe.contentDocument).document.body;

第一眼看到这行代码,不知道是获取什么,先把 uploadIframe.contentWindow 和 uploadIframe.contentDocument 这两个打印输出一下,看一下是什么东西,在代码里面加入console.log()代码,再上传图片看看!

由于调用uploadIframe.contentWindow会报跨域错误,所以,只能看到uploadIframe.contentDocument的值为null

所以,无法得到uploadIframe.contentWindow的值,经过一番百度搜索,知道这个值其实就是Editor.md配置的服务器请求接口值

然后,再进一步了解到,image-dialog.js这个文件访问图片上传中的数据造成的跨域问题。

知道了问题所在,就好办了,开始分析源码。

在该函数的接下一行:会调用该函数

dialog.find("[type=\"submit\"]").bind("click", submitHandler).trigger("click");

首先,是寻找一个type类型是submit提交的元素,然后绑定事件click点击调用submitHandler函数

我们来输出一下,这行代码找到的sunmit的元素是什么:

console.log(dialog.find("[type=\"submit\"]"));

得到一个对象,分析一下

大概就是创建一个表单,上传到接口,接着继续在image-dialog.js中寻找与表单有关的代码,相关的有如下代码:

var dialogContent = ( (settings.imageUpload) ? "<form action=\"" + action +"\" target=\"" + iframeName + "\" method=\"post\" enctype=\"multipart/form-data\" class=\"" + classPrefix + "form\">" : "<div class=\"" + classPrefix + "form\">" ) +
                                        ( (settings.imageUpload) ? "<iframe name=\"" + iframeName + "\" id=\"" + iframeName + "\" guid=\"" + guid + "\"></iframe>" : "" ) +
                                        "<label>" + imageLang.url + "</label>" +
                                        "<input type=\"text\" data-url />" + (function(){
                                            return (settings.imageUpload) ? "<div class=\"" + classPrefix + "file-input\">" +
                                                                                "<input type=\"file\" name=\"" + classPrefix + "image-file\" accept=\"image/*\" />" +
                                                                                "<input type=\"submit\" value=\"" + imageLang.uploadButton + "\" />" +
                                                                            "</div>" : "";
                                        })() +
                                        "<br/>" +
                                        "<label>" + imageLang.alt + "</label>" +
                                        "<input type=\"text\" value=\"" + selection + "\" data-alt />" +
                                        "<br/>" +
                                        "<label>" + imageLang.link + "</label>" +
                                        "<input type=\"text\" value=\"http://\" data-link />" +
                                        "<br/>" +
                                    ( (settings.imageUpload) ? "</form>" : "</div>");

分析一下,应该就是获取前端的表单,然后再创建一个表单提交到后端中,但是由于前端的表单和image-dialog.js不是同源,所以会报跨域错误!!

分析:

既然用表单提交会报错,那么就采用ajax来提交!!

首先,去掉前端js中的图片接口配置!

/**上传图片相关配置如下*/
imageUpload : true,
imageFormats : ["jpg", "jpeg", "gif", "png", "bmp", "webp"],
// imageUploadURL : baseUrl+'/upload/test',//注意你后端的上传图片服务地址

未去掉之前:

去掉之后:

为什么还有guid呢,分析了image-dialog.js发现,这是自动生成的时间戳!

var guid   = (new Date).getTime();
var action = settings.imageUploadURL + (settings.imageUploadURL.indexOf("?") >= 0 ? "&" : "?") + "guid=" + guid;

我们只需要修改action方法即可!

未修改之前:

if (settings.crossDomainUpload)
{
action += "&callback=" + settings.uploadCallbackURL + "&dialog_id=editormd-image-dialog-" + guid;
}

修改之后:

action ="";

此时还需要关闭本地上传的默认提交功能:

var submitHandler = function() {

var uploadIframe = document.getElementById(iframeName);

uploadIframe.onload = function() {

loading(false);
var body = (uploadIframe.contentWindow ? uploadIframe.contentWindow : uploadIframe.contentDocument).document.body;
var json = (body.innerText) ? body.innerText : ( (body.textContent) ? body.textContent : null);

json = (typeof JSON.parse !== "undefined") ? JSON.parse(json) : eval("(" + json + ")");

if(!settings.crossDomainUpload)
{
if (json.success === 1)
{
dialog.find("[data-url]").val(json.url);
}
else
{
alert(json.message);
}
}

return false;
};
loading(false);//新增这里
return false;//新增这里
};

此时,我们应该留意到uploadIframe.onload = function()里面有三个参数:success、message、url 对应Editor.md中提示的参数

// {
//     success : 0 | 1,           // 0 表示上传失败,1 表示上传成功
//     message : "提示的信息,上传成功或上传失败及错误信息等。",
//     url     : "图片地址"        // 上传成功时才返回
// }

继续看uploadIframe.onload = function() 里面的代码:

loading(false);//加载关闭
var body = (uploadIframe.contentWindow ? uploadIframe.contentWindow : uploadIframe.contentDocument).document.body;//跨域获取action的接口数据
var json = (body.innerText) ? body.innerText : ( (body.textContent) ? body.textContent : null);
json = (typeof JSON.parse !== "undefined") ? JSON.parse(json) : eval("(" + json + ")");
if(!settings.crossDomainUpload)
{
if (json.success === 1)
{
dialog.find("[data-url]").val(json.url);//???在函数头打印输出一下
}
else
{
alert(json.message);
}
}
return false;

发现find寻找这个元素是 图片地址 那一栏!作用就是将服务器返回的json格式数据url填入!

解决:

分析完毕,开始采用ajax代替原来的form表单提交!

首先把var submitHandler = function()函数的代码都注释掉:

var submitHandler = function() {

// var uploadIframe = document.getElementById(iframeName);

// uploadIframe.onload = function() {

//     loading(false);
//     var body = (uploadIframe.contentWindow ? uploadIframe.contentWindow : uploadIframe.contentDocument).document.body;
//     var json = (body.innerText) ? body.innerText : ( (body.textContent) ? body.textContent : null);

//     json = (typeof JSON.parse !== "undefined") ? JSON.parse(json) : eval("(" + json + ")");

//     if(!settings.crossDomainUpload)
//     {
//       if (json.success === 1)
//       {
//           dialog.find("[data-url]").val(json.url);
//       }
//       else
//       {
//           alert(json.message);
//       }
//     }

//     return false;
// };
loading(false);
return false;
};

改为:

var submitHandler = function() {

	var form = dialog.find("[enctype=\"multipart/form-data\"]")[0];
	var formData = new FormData(form);
	$.ajax({
		type: 'post',
		// url: "http://localhost:8080/upload/test", // 你的服务器端的图片上传接口。如果你设置了 imageUploadURL,那么可以使用下面的方式
		url: settings.imageUploadURL + (settings.imageUploadURL.indexOf("?") >= 0 ? "&" : "?") + "guid=" + guid,
		data: formData,
		cache: false,
		processData: false,
		contentType: false,
		success: function(data, textStatus, jqXHR) {
			// console.log(data);
			// console.log(textStatus);
			// console.log(jqXHR);
			if (data.success === 1) { // 上传成功
				dialog.find("[data-url]").val(data.url); // 设置图片地址
			}
			else {
				alert(data.message); // 上传失败,弹出警告信息
			}
		},
		error: function(XMLHttpRequest, textStatus, errorThrown) {
			// console.log(XMLHttpRequest);
			// console.log(textStatus);
			// console.log(errorThrown);
		}
	});

	loading(false);
	return false;
};

结果:

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页