[WebApi] 捣鼓一个资源管理器–文件下载

最后更新于:2022-04-01 06:57:05

# In This 访问一个网上的图片资源,我想你应该遇到过这样的情况: 常规情况下:[http://www.qiujuer.net/Statics/Image/Home/HeadPortrait.png](http://www.qiujuer.net/Statics/Image/Home/HeadPortrait.png) 当然还有这样:[http://www.qiujuer.net/Resource/75CDF243C30750D397A90E58D412B22E](http://www.qiujuer.net/Resource/75CDF243C30750D397A90E58D412B22E) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_56935659c29b4.jpg) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_56935659f0dbd.jpg) 可以看到得到同样的一张图片却能采用不一样的地址,特别是在第二个地址中却没有文件的后缀。 这个奇葩了吧?有感觉到很奇怪的么? ##### 其实很简单 在**第一种情况**中是访问的当前图片存储在网站服务器中的地址。 换言之其在”cdn.duitang.com“网站的服务器中存储的地址应该是文件夹"uploads/item/201403/04”下的“20140304122431_XMCuj.jpeg”文件。 而输入第一张图片中的地址的时候,web服务器将会在其指定文件夹下去搜寻该文件,然后返回图片。 而**第二种情况**中你能说是在”www.qiujuer.net“网站的“Resource”文件夹下的”75CDF243C30750D397A90E58D412B22E“文件么? 有这样的可能,但是在这个情况下不是! 其工作原理是访问当前URL的时候触发的是“Resource”接口,然后传入了ID=”75CDF243C30750D397A90E58D412B22E“。 然后WebApi服务器根据该ID通过一定的方式去寻找图片资源,然后通过资源的方式返回图片; 而其图片究竟是存在哪里你并不知道,有可能是在当前网站目录下的某个文件夹,也可能是其他盘;总之是不固定的。 请问针对第二种情况你能使用爬虫软件去爬该图片么?如果可以;但是我给这个接口加上指定的用户权限呢? 说了这么多,我们来实现一下! # CodeTime 首先打开VS-新建项目-web应用程序-名称“WebResource”-WebApi ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_5693565a24c68.jpg) 进入项目-删除**ValuesController** 添加一个webapi控制器-**ResourceApiController** ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_5693565a3ace9.jpg) 在其中实现Get方法: ~~~     [RoutePrefix("Resource")]     public class ResourceApiController : ApiController     {         private static readonly long MEMORY_SIZE = 64 * 1024 * 1024;         private static readonly string ROOT_PATH = HttpContext.Current.Server.MapPath("~/App_Data/");         [HttpGet]         [Route("{Id}")]         public async Task<HttpResponseMessage> Get(string Id)         {             // 进入时判断当前请求中是否含有 ETag 标识,如果有就返回使用浏览器缓存             // Return 304             var tag = Request.Headers.IfNoneMatch.FirstOrDefault();             if (Request.Headers.IfModifiedSince.HasValue && tag != null && tag.Tag.Length > 0)                 return new HttpResponseMessage(HttpStatusCode.NotModified);             // 进行模拟 App_Data/Image/{id}.png             // 打开找到文件             FileInfo info = new FileInfo(Path.Combine(ROOT_PATH, "Image", Id + ".png"));             if (!info.Exists)                 return new HttpResponseMessage(HttpStatusCode.BadRequest);             FileStream file = null;             try             {                 // 打开文件                 file = new FileStream(info.FullName, FileMode.Open, FileAccess.Read, FileShare.Read);                 HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);                 // 在浏览器中显示 inline                 ContentDispositionHeaderValue disposition = new ContentDispositionHeaderValue("inline");                 // 写入文件基本信息                 disposition.FileName = file.Name;                 disposition.Name = file.Name;                 disposition.Size = file.Length;                 // 判断是否大于64Md,如果大于就采用分段流返回,否则直接返回                 if (file.Length < MEMORY_SIZE)                 {                     //Copy To Memory And Close.                     byte[] bytes = new byte[file.Length];                     await file.ReadAsync(bytes, 0, (int)file.Length);                     file.Close();                     MemoryStream ms = new MemoryStream(bytes);                     result.Content = new ByteArrayContent(ms.ToArray());                 }                 else                 {                     result.Content = new StreamContent(file);                 }                 // 写入文件类型,这里是图片png                 result.Content.Headers.ContentType = new MediaTypeHeaderValue("image/png");                 result.Content.Headers.ContentDisposition = disposition;                 // 设置缓存信息,该部分可以没有,该部分主要是用于与开始部分结合以便浏览器使用304缓存                 // Set Cache                 result.Content.Headers.Expires = new DateTimeOffset(DateTime.Now).AddHours(1);                 // 这里应该写入文件的存储日期                 result.Content.Headers.LastModified = new DateTimeOffset(DateTime.Now);                 result.Headers.CacheControl = new CacheControlHeaderValue() { Public = true, MaxAge = TimeSpan.FromHours(1) };                 // 设置Etag,这里就简单采用 Id                 result.Headers.ETag = new EntityTagHeaderValue(string.Format("\"{0}\"", Id));                 // 返回请求                 return result;             }             catch             {                 if (file != null)                 {                     file.Close();                 }             }             return new HttpResponseMessage(HttpStatusCode.BadRequest);         }     } ~~~ 基本上都进行了注释,如果有不了解的还请评论中写下。 # RunTime ### 准备工作 在运行前我们需要在“**App_Data**”下建立文件夹“**Image**”。然后拷贝两张图片“**001.png**”\"002.png"进去。 ### 运行 点击运行-浏览器中输入URL:http://localhost:60586/Resource/001 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_5693565a541a9.jpg) 把ID换成002再次输入:http://localhost:60586/Resource/002 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_5693565a7c9e5.jpg) OK,基本的功能我们实现了。 # END Time ### 为什么是“App_Data”文件夹? 在这里有必要说的是“App_Data”在.NET Web 中是受保护的对象。无法直接通过URL访问;不信? 来试试,输入URL:http://localhost:60586/App_Data/Image/002.png ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-11_5693565a9e561.jpg) 所以说,一般数据库文件是可以放在该文件夹下的;当然现在你可以把图片放在下面,然后通过接口访问。 ### 是否太简单了? 的确,在这里第一章只是一个开始;后面会逐渐的进行扩大化。 比如增加:上传、其他非图片文件、以及不是001,002等名称,而是运算一个Id出来、当然还有加上数据的管理等等。 ### 代码 这次的代码打包了;但是CSDN死活传不上去,我去啊!不过好在也简单;就一个方法;下一章中一起打包吧。 ### 下一章 下一章已经更新,资源文件也在下一章中; [[WebApi] 捣鼓一个资源管理器--多文件上传](http://blog.csdn.net/qiujuer/article/details/41675299)
';