以Base64字符串形式上传文件——在web浏览器端使用原生Javascript及Ajax读取本地文件并发送请求到服务器

简述

在常规的web开发过程中,大部分上传文件都是在web页面端通过表单直接提交,再由服务器端捕获请求来进行处理的。但是在前后端分离趋于一种流行趋势,再加上Android和iOS开发技术日渐成熟,大部分团队都会选择在服务器端仅提供一套通用的webservice数据接口,而web页面、Android和iOS统一都通过这套数据接口来向服务器发送请求和获取数据。

在这一过程中,大部分的webservice数据接口都会采用xml数据格式或是json数据格式来进行数据请求和处理,在这种情况下,其实来自客户端的请求就可以看作是一个字符串(无论是xml还是json数据)。此时,常规的数据提交完全不存在任何问题,但是附件上传就需要特殊处理了。


本文简单介绍了如何在web页面端采用Ajax的方式来读取本地的文件,并转换成Base64字符串,以及如何将字符串提交到服务器。

一、定义文件内容变量

我们顺着思路一步一步开始,为了更好地方便理解,我们全部采用原生javascript和原生ajax代码,不使用任何第三方类库或组件。

首先,我们需要定义一个变量,这个变量用来记录需要上传到服务器的本地文件的字符串内容:
var fileStringBase64;

二、获取本地文件,并转换为Base64形式的字符串

然后,我们定义一个方法,这个方法用来将用户选取的本地文件转换成Base64字符串:
function getStringFromFile(e){
	//获取文件
	var file = e.target.files[0];

	/*
	 * 使用FileReader对象将文件转换为Base64字符串
	 */
	var reader = new FileReader();
	reader.readAsDataURL(this.file,"UTF-8");
	reader.onload=function(){
		fileStringBase64 = this.result;
		fileStringBase64 = fileStringBase64.substring(fileStringBase64.indexOf(",")+1,fileStringBase64.length);
	}
}



注意,在上面的代码中,我们在最后对字符串进行了一次substring操作,目的是去掉字符串中的文件头信息,只保留文件的正文字符串。
另一个特别需要注意的地方是,较早的一些古老的浏览器可能并不支持FileReader对象,例如某些政府部门的内部信息体系仍然在使用WindowsXP及老式ie浏览器。针对这种情况,本方法就没有效果了。

最后,我们在<input type="file"/>中定义触发时间,调用上述方法即可:
<input type="file" onchange="getStringFromFile()">

这样一来,用户所选择的本地文件就会被转换成一个字符串,并且保存在变量“fileStringBase64”中了。

三、向服务器发送请求

我们以原生Ajax的方式来向服务器端发送文件,
首先,创建一个request请求对象:
var http_request = false;
if (window.XMLHttpRequest) { // Mozilla, Safari等非IE的浏览器
	 http_request = new XMLHttpRequest();
  	if (http_request.overrideMimeType) {
		http_request.overrideMimeType('text/xml');
	}
} else if (window.ActiveXObject) { // IE浏览器
	try {
		http_request = new ActiveXObject("Msxml2.XMLHTTP");
	} catch (e) {
		try {
			 http_request = new ActiveXObject("Microsoft.XMLHTTP");
		} catch (e) {}
	}
}
 
if (!http_request) {
	alert("无法创建基于XmlHttp的Ajax请求对象");
	return false;
}

然后,就是向服务器端发送请求了,这里分为4个步骤:
第一步:定义响应回调方法:
http_request.onreadystatechange = function(){
	if (http_request.readyState == 4) {
		if (http_request.status == 200) {
			alert(http_request.responseText);
		} else {
			alert("请求出现问题,状态码:"+http_request.status);
		}
	}
};

第二步:设置请求方式及服务器地址:
http_request.open("POST", "在这里输入服务器地址", true);//以post形式发送请求

第三步:设置请求头:
http_request.setRequestHeader('Content-Type', 'text/plain;charset=utf-8');
注意,我们使用的是“text/plain”的方式,即以流的形式向服务器发送请求数据。

第四步:设置请求数据:
http_request.send(fileStringBase64); 
这这一步,我们将已经变成了字符串形式的文件内容作为向服务器发送的请求数据。


上面这几段关于原生Ajax的代码非常固定,至少在我十几年的码农生涯中,这段原生Ajax代码完全没有变化过,从最早的ie6浏览器一直到目前的所有主流浏览器都完全支持。你完全可以从Google或者baidu中搜索到一模一样的代码,因为原生Ajax就是这么固定。
唯一有点可惜的是,经历过jQuery为代表的第三方类库的发展,一直到现今的更多流行的mvvm前端框架设计思想和组件,越来越多的年轻前端开发人员疏忽了原生javascript和原生ajax的力量——其实那才是“洪荒之力”。

说跑题了。

基于上述的思路,我整理了一个完整的原生Ajax方法,和一个配套的原生回调方法:
/**
 * 向服务器发起ajax请求
 * 方法的入参说明如下:
 * paramIn:发送给服务器端的请求参数
 * urlIn:服务器端webservice地址
 * callbackFuncIn:当完成请求以后,调用的用以处理服务器响应参数的回调方法的方法名,该方法接收一个HTTP_REQUEST对象作为入参
 */
function baseRequest(paramIn,urlIn,callbackFuncIn){
	var http_request = false;
	if (window.XMLHttpRequest) { // Mozilla, Safari等非IE的浏览器
		 http_request = new XMLHttpRequest();
	  	if (http_request.overrideMimeType) {
			http_request.overrideMimeType('text/xml');
		}
	} else if (window.ActiveXObject) { // IE浏览器
		try {
			http_request = new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try {
				 http_request = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (e) {}
		}
	}
	 
	if (!http_request) {
		alert("无法创建基于XmlHttp的Ajax请求对象");
		return false;
	}
	
	http_request.onreadystatechange = function(){baseCallback(http_request,callbackFuncIn)};
	http_request.open("POST", urlIn, true);
	http_request.setRequestHeader('Content-Type', 'text/plain;charset=utf-8');
	http_request.send(paramIn); 
}

/**
 * 向服务器发起ajax的请求后,接受服务器的响应参数,并调用用户自定义的回调处理方法
 * 方法的入参说明如下:
 * httpRequestIn:发送给服务器端的请求对象
 * callbackFuncIn:当完成请求以后,调用的用以处理服务器响应参数的回调方法的方法名,该方法接收一个HTTP_REQUEST对象作为入参
 */
function baseCallback(httpRequestIn,callbackFuncIn){
	if (httpRequestIn.readyState == 4) {
		if (httpRequestIn.status == 200) {
			callbackFuncIn(httpRequestIn);
		} else {
			alert("请求出现问题,状态码:"+httpRequestIn.status);
		}
	}
}

然后,我们只需要直接调用这个原生方法就可以了:
baseRequest("字符串形式的文件内容",
	"服务器地址",
	自定义响应回调方法);


四、服务器端接收文件

关于如何在服务器端接收请求,并将字符串还原成文件,请看以下链接内容:

猜你喜欢

转载自blog.csdn.net/freezingxu/article/details/77922367
今日推荐