对于需要经常上传文件的站点,为了保证文件安全性,不会把文件上传到站点下,而是把文件上传到指定的文件服务器,这里主要讲一下通过http协议上传文件。
http协议的文件上传,我目前接触到的又有两种方式:一是IIS文件上传机制,二是跨域文件上传。
本文主要讲的是IIS文件上传机制。
1.先将文件上传到应用服务器。
HTML
<div class="layui-fluid">
<div class="">
<div class="col_title"> ajax上传文件到文件服务器-通过IIS上传文件</div>
<div class="btn_file">
<button type="button" class="layui-btn" id="btn_file" onclick="f_flie.click();"> <i class="layui-icon"> </i> 上传图片</button>
<input type="file" id="f_flie" multiple="multiple" accept="image/jpg,image/jpeg,image/png" style="display:none;" onchange="UpfileCheck(this)" />
</div>
<div class="preview_img_files">
</div>
</div>
</div>
JS
<script src="/js/layui/layui.js"></script>
<script src="/js/jquery/jquery-3.2.1.min.js"></script>
<script type="text/javascript">
var fl = 0;//文件数量
var upload_num = 0;//文件上传索引
//文件上传初始化
function UpfileCheck(t) {
fl = t.files.length;//获取文件数量
upload_num = 0;//初始化文件上传索引
//需要判断是否选择图片,否则第一次选择图片后,第二次选择图片取消也会触发上传
if (fl > 0) {
upload_mask = layer.load(1, {
content: '上传中...',
shade: [0.4, '#393D49'],
success: function (layero) {
layero.find('.layui-layer-content').css({
'padding-top': '39px',
'width': '200px',
'color': '#fff',
'text-align': 'left'
});
}
});
setTimeout(function () { UpfileFiles(t, upload_num); }, 500);
}
else {
layer.msg('请选择需要上传的文件!');
}
}
//使用file对象上传文件
function UpfileFiles(t, f_num) {
var imgData = new FormData();
imgData.append('fun', 'UploadImgFilesServer');//文件上传方法名
imgData.append('file', t.files[f_num]);//file对象
imgData.append('src', "/upload/img/");//上传文件存放地址
$.ajax({
type: "POST",
url: "/UploadFile/ashx/UploadImg.ashx",
data: imgData,
processData: false,//防止将发送的数据序列
contentType: false,//默认值: true。默认情况下,通过data选项传递进来的数据,如果是一个对象(技术上讲只要不是字符串),都会处理转化成一个查询字符串,以配合默认内容类型 “application/x-www-form-urlencoded”。如果要发送 DOM 树信息或其它不希望转换的信息,请设置为 false。
dataType: "json",
async: false,
success: function (data) {
PreviewBImg(data.ajaxresult);//预览图片
upload_num++;//更新文件索引
//文件未上传完成继续上传
if (upload_num < fl) {
UpfileFiles(t, upload_num);//继续上传
}
else {
layer.close(upload_mask);
}
},
error: function (event, XMLHttpRequest, ajaxOptions, thrownError) {
// thrownError 只有当异常发生时才会被传递 this;
var resStr = event.statusText
layer.msg("上传失败:" + resStr);
}
})
}
//预览图片
function PreviewBImg(src) {
var htmlimg = "<img src='" + src + "' />";
$(".preview_img_files").append(htmlimg);
}
</script>
通过一般处理程序将文件上传到应用服务器
public string UploadImgFiles(HttpContext context)
{
HttpPostedFile files = context.Request.Files["file"];
string src = context.Request.QueryString["src"] ?? context.Request.Form["src"];
try
{
//文件上传路径+年月日
src = src + DateTime.Now.ToString("yyMMdd") + "/";
string uploadPath = context.Request.PhysicalApplicationPath + src;//获取文件在应用服务器存放的绝对路径
//判断文件上传路径文件夹是否存在
if (!Directory.Exists(uploadPath))
{
Directory.CreateDirectory(uploadPath);//创建文件夹
}
//上传文件至应用服务器
files.SaveAs(uploadPath + files.FileName);
Image pic = Image.FromFile(uploadPath + files.FileName);//图片的绝对路径
int intWidth = pic.Width;//长度像素值
int intHeight = pic.Height;//高度像素值
pic.Dispose();//释放资源
//文件HTTP路径,域名+端口+文件上传路径+文件名
string httpPath = "http://" + context.Request.Url.Host + ":" + context.Request.Url.Port + src + files.FileName;
at.ajaxDataFlag = true;
at.ajaxresult = httpPath;
at.ajaxString = uploadPath + files.FileName;//文件在应用服务器的绝对路径
}
catch (Exception ex)
{
at.ajaxDataFlag = false;
at.ajaxresult = "服务器内部错误,请联系开发人员!";
ALogOut.debug(ex.ToString());
}
return JsonConvert.SerializeObject(at);
}
2.将文件上传到文件服务器
public string UploadImgFilesServer(HttpContext context)
{
string AuthFlag = "";//认证类型,0:window身份认证,1:匿名身份认证
string AuthUser = "";//匿名身份认证特定用户名
string AuthPwd = "";//匿名身份认证特定密码
string httpurl = "";//文件上传到文件服务器的http地址
string fileurl = "";//文件在应用服务器的绝对路径
HttpPostedFile files = context.Request.Files["file"];
try
{
//将文件先上传到应用服务器
string JsonString = UploadImgFiles(context);
var result = JsonConvert.DeserializeObject<Dictionary<string, object>>(JsonString);//反序列化获取文件上传到应用服务器的结果(json字符串存在null值,转换失败解决方案)
bool resultDataFlag = Convert.ToBoolean(result["ajaxDataFlag"].ToString());
if (resultDataFlag == false)
{
at.ajaxDataFlag = false;
at.ajaxresult = "服务器内部错误,请联系开发人员!";
return JsonConvert.SerializeObject(at);//如果文件上传到应用服务器的出错,则返回结果
}
else
{
//如果文件上传到应用服务器成功,则上传到文件服务器
fileurl = result["ajaxString"].ToString();//文件在应用服务器的绝对路径
WebClient client = new WebClient();
AuthFlag = System.Configuration.ConfigurationManager.AppSettings["AuthFlag"].ToString();//认证类型,0:window身份认证,1:匿名身份认证
httpurl = System.Configuration.ConfigurationManager.AppSettings["PhotoFileUrl"].ToString() + files.FileName;//文件上传地址(文件服务)
if (AuthFlag == "1")
{
//AuthFlag:1,匿名身份认证:当应用服务器和文件服务器不在同一台服务器时,IIS会启用匿名身份认证
if (System.Configuration.ConfigurationManager.AppSettings["AuthUser"] == null || System.Configuration.ConfigurationManager.AppSettings["AuthPwd"] == null)
{
at.ajaxDataFlag = false;
at.ajaxresult = "未配置匿名身份认证特定用户名或密码,请联系管理员!";
return JsonConvert.SerializeObject(at);
}
else
{
AuthUser = System.Configuration.ConfigurationManager.AppSettings["AuthUser"];
AuthPwd = System.Configuration.ConfigurationManager.AppSettings["AuthPwd"];
}
client.Credentials = new NetworkCredential(AuthUser, AuthPwd);//发送身份认证凭证
}
else if (AuthFlag == "0")
{
//AuthFlag:0,window身份认证:在应用服务器和文件服务器在同一台服务器时,IIS会启用window身份认证
if (System.Configuration.ConfigurationManager.AppSettings["PhotoFileHttp"] == null || System.Configuration.ConfigurationManager.AppSettings["PhotoFileIP"] == null)
{
at.ajaxDataFlag = false;
at.ajaxresult = "未配置文件服务器域名或者文件服务器IP地址,请联系管理员!";
return JsonConvert.SerializeObject(at);
}
else
{
//如果文件服务器和应用服务器发布在同一台服务器上,并且端口相同,需要给文件服务器添加一个不一样的端口,并且将文件上传的地址中的域名替换成该IP+端口的地址
string PhotoFileHttp = System.Configuration.ConfigurationManager.AppSettings["PhotoFileHttp"].ToString();
string PhotoFileIP = System.Configuration.ConfigurationManager.AppSettings["PhotoFileIP"].ToString();
httpurl = httpurl.Replace(PhotoFileHttp, PhotoFileIP);
}
client.Credentials = CredentialCache.DefaultCredentials;//发送身份认证凭证
}
else
{
at.ajaxDataFlag = false;
at.ajaxresult = "未配置身份认证类型!";
return JsonConvert.SerializeObject(at);
}
//client.Headers.Add("Content-Type", "application/form-data");//注意头部必须是form-data
client.Headers.Add("http-method", "LOCK");
client.Headers.Add("http-method", "DELETE");
client.Headers.Add("http-method", "MOVE");
client.Headers.Add("http-method", "TRACE");
Stream postStream = client.OpenWrite(httpurl, "PUT");
FileStream fs = new FileStream(fileurl, FileMode.Open, FileAccess.Read);
BinaryReader r = new BinaryReader(fs);
byte[] postArray = r.ReadBytes((int)fs.Length);
if (postStream.CanWrite)
{
postStream.Write(postArray, 0, postArray.Length);
}
else
{
at.ajaxDataFlag = false;
at.ajaxresult = "文件没有权限,请联系管理员!";
return JsonConvert.SerializeObject(at);
}
postStream.Close();
client.Dispose();
fs.Dispose();
File.Delete(fileurl);//删除上传至应用服务器的文件
}
at.ajaxDataFlag = true;
at.ajaxresult = httpurl;
}
catch (Exception ex)
{
at.ajaxDataFlag = false;
at.ajaxresult = "服务器内部错误,请联系开发人员!";
ALogOut.debug(ex.ToString());
}
return JsonConvert.SerializeObject(at);
}
2.1.window身份认证
文件上传到文件服务器时,如果应用服务器和文件服务器在同一台服务器,IIS会启用“window身份认证”。
这里会有个比较变态的问题,就是应用站点和文件服务器站点用域名发布后,默认为80端口,这时候上传文件会出现错误403,需要在文件服务器新增一个IP+端口的网站绑定,将文件域名的上传地址替换成IP+端口的地址,就可以解决这个问题。
//AuthFlag:0,window身份认证:在应用服务器和文件服务器在同一台服务器时,IIS会启用window身份认证
if (System.Configuration.ConfigurationManager.AppSettings["PhotoFileHttp"] == null || System.Configuration.ConfigurationManager.AppSettings["PhotoFileIP"] == null)
{
at.ajaxDataFlag = false;
at.ajaxresult = "未配置文件服务器域名或者文件服务器IP地址,请联系管理员!";
return JsonConvert.SerializeObject(at);
}
else
{
//如果文件服务器和应用服务器发布在同一台服务器上,并且端口相同,需要给文件服务器添加一个不一样的端口,并且将文件上传的地址中的域名替换成该IP+端口的地址
string PhotoFileHttp = System.Configuration.ConfigurationManager.AppSettings["PhotoFileHttp"].ToString();
string PhotoFileIP = System.Configuration.ConfigurationManager.AppSettings["PhotoFileIP"].ToString();
httpurl = httpurl.Replace(PhotoFileHttp, PhotoFileIP);
}
client.Credentials = CredentialCache.DefaultCredentials;//发送身份认证凭证
2.2.匿名身份认证
文件上传到文件服务器时,如果应用服务器和文件服务器在不在同一台服务器,IIS会启用“匿名身份认证”,这里主要需要对IIS进行配置。
IIS配置和常见错误解决办法:
错误401
错误原因
从IIS 7.0开始,不允许匿名写入WebDAV发布目录。具体来说,PUT,MKCOL,PROPPATCH,COPY,MOVE,DELETE和基于WebDAV的GET请求都需要身份验证。
解决方案
1.创建计算机用户,分配管理员权限,设置用于隶属于组;
2.打开IIS选中站点,进入身份验证,右键点击匿名身份验证,选择编辑,同时选择特定用户,输入刚刚添加的用户;
3.右键点击IIS发布的网站,选择编辑权限,将刚刚添加的用户分配完全控制权限;
4。点击IIS界面右侧基本设置,点击连接为,并选中特定用户,点击设置输入刚刚创建的用户名和密码;
5.设置身份认证凭证,这里的用户名、密码需要和IIS基本设置的特定用户的用户名和密码相同。
//AuthFlag:1,匿名身份认证:当应用服务器和文件服务器不在同一台服务器时,IIS会启用匿名身份认证
if (System.Configuration.ConfigurationManager.AppSettings["AuthUser"] == null || System.Configuration.ConfigurationManager.AppSettings["AuthPwd"] == null)
{
at.ajaxDataFlag = false;
at.ajaxresult = "未配置匿名身份认证特定用户名或密码,请联系管理员!";
return JsonConvert.SerializeObject(at);
}
else
{
AuthUser = System.Configuration.ConfigurationManager.AppSettings["AuthUser"];
AuthPwd = System.Configuration.ConfigurationManager.AppSettings["AuthPwd"];
}
client.Credentials = new NetworkCredential(AuthUser, AuthPwd);//发送身份认证凭证
错误405
1.选择IIS的WebDAV创作规则,
2.点击启用WebDAV
错误403
1.选择IIS的WebDAV创作规则,
2.选择添加创作规则
3.按照如图所示操作后,点击确定
错误409
文件路径不存在;
总结
优点:不会影响其他站点的文件,安全性较高;
缺点:因为需要把文件上传到应用服务器,再上传到文件服务器,相当于上传了两次,如果碰到大文件或多文件上,传效率较低。