ASP.NET Core의 정적 파일
참고 항목
이 문서의 최신 버전은 아닙니다. 현재 릴리스는 이 문서의 .NET 8 버전을 참조 하세요.
Important
이 정보는 상업적으로 출시되기 전에 실질적으로 수정될 수 있는 시험판 제품과 관련이 있습니다. Microsoft는 여기에 제공된 정보에 대해 어떠한 명시적, 또는 묵시적인 보증을 하지 않습니다.
현재 릴리스는 이 문서의 .NET 8 버전을 참조 하세요.
작성자: Rick Anderson
HTML, CSS, 이미지 및 JavaScript와 같은 정적 파일은 기본적으로 ASP.NET Core 앱이 클라이언트에 직접 제공하는 자산입니다.
Blazor 이 문서의 지침을 추가하거나 대체하는 정적 파일 지침은 ASP.NET Core Blazor 정적 파일을 참조하세요.
정적 파일 제공
정적 파일은 프로젝트의 웹 루트 디렉터리 내에 저장됩니다. 기본 디렉터리는 {content root}/wwwroot
이지만, UseWebRoot 메서드를 통해 변경할 수 있습니다. 자세한 내용은 콘텐츠 루트 및 웹 루트를 참조하세요.
CreateBuilder 메서드는 콘텐츠 루트를 현재 디렉터리로 설정합니다.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.MapStaticAssets();
app.UseAuthorization();
app.MapDefaultControllerRoute().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
정적 파일은 웹 루트에 상대적인 경로를 통해 액세스할 수 있습니다. 예를 들어 웹 애플리케이션 프로젝트 템플릿에는 wwwroot
폴더 내에 여러 폴더가 포함되어 있습니다.
wwwroot
css
js
lib
파일이 있는 앱을 고려합니다 wwwroot/images/MyImage.jpg
. images
폴더의 파일에 액세스하기 위한 URI 형식은 https://<hostname>/images/<image_file_name>
입니다. 예를 들어 https://localhost:5001/images/MyImage.jpg
MapStaticAssets
성능이 좋은 웹앱을 만들려면 브라우저에 대한 자산 배달을 최적화해야 합니다. 가능한 최적화는 다음과 같습니다.
- 파일이 변경되거나 브라우저가 캐시를 지울 때까지 지정된 자산을 한 번 제공합니다. ETag 헤더를 설정합니다.
- 앱이 업데이트된 후 브라우저에서 이전 또는 부실 자산을 사용하지 못하도록 합니다. 마지막으로 수정한 헤더를 설정합니다.
- 적절한 캐싱 헤더를 설정합니다.
- 캐싱 미들웨어를 사용합니다.
- 가능하면 압축된 버전의 자산을 제공합니다.
- CDN을 사용하여 사용자에게 더 가까운 자산을 제공합니다.
- 브라우저에 제공되는 자산의 크기를 최소화합니다. 이 최적화에는 축소가 포함되지 않습니다.
MapStaticAssets 는 앱에서 정적 자산의 배달을 최적화하는 라우팅 엔드포인트 규칙입니다. 페이지 및 MVC를 비롯한 BlazorRazor 모든 UI 프레임워크에서 작동하도록 설계되었습니다.
UseStaticFiles
또한 정적 파일을 제공하지만 MapStaticAssets
. 비교 UseStaticFiles
및 MapStaticAssets
비교는 정적 웹 자산 배달 최적화를 참조하세요.
웹 루트의 파일 제공
기본 웹앱 템플릿은 Program.cs
에서 MapStaticAssets 메서드를 호출하여 정적 파일을 제공할 수 있습니다.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.MapStaticAssets();
app.UseAuthorization();
app.MapDefaultControllerRoute().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
매개 변수가 없는 UseStaticFiles
메서드 오버로드는 웹 루트에 있는 파일을 제공 가능으로 표시합니다. 다음 태그 참조는 다음과 같습니다.wwwroot/images/MyImage.jpg
<img src="~/images/MyImage.jpg" class="img" alt="My image" />
위의 태그에서 물결표 문자(~
)는 웹 루트를 가리킵니다.
웹 루트 외부의 파일 제공
제공할 정적 파일이 웹 루트 외부에 있는 디렉터리 계층 구조를 고려해보세요.
wwwroot
css
images
js
MyStaticFiles
images
red-rose.jpg
요청은 정적 파일 미들웨어를 다음과 같이 구성하여 red-rose.jpg
파일에 액세스할 수 있습니다.
using Microsoft.Extensions.FileProviders;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles(); //Serve files from wwwroot
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
RequestPath = "/StaticFiles"
});
app.UseAuthorization();
app.MapDefaultControllerRoute().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
위의 코드에서 MyStaticFiles 디렉터리 계층 구조는 StaticFiles URI 세그먼트를 통해 공개적으로 노출됩니다. 파일을 제공하는 https://<hostname>/StaticFiles/images/red-rose.jpg
요청입니다 red-rose.jpg
.
다음 태그 참조는 다음과 같습니다.MyStaticFiles/images/red-rose.jpg
<img src="~/StaticFiles/images/red-rose.jpg" class="img" alt="A red rose" />
여러 위치에서 파일을 제공하려면 여러 위치에서 파일 제공을 참조하세요.
HTTP 응답 헤더 설정
StaticFileOptions 개체를 사용하여 HTTP 응답 헤더를 설정할 수 있습니다. 다음 코드는 웹 루트에서 제공되는 정적 파일을 구성하는 것 외에도 Cache-Control 헤더를 설정합니다.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
var cacheMaxAgeOneWeek = (60 * 60 * 24 * 7).ToString();
app.UseStaticFiles(new StaticFileOptions
{
OnPrepareResponse = ctx =>
{
ctx.Context.Response.Headers.Append(
"Cache-Control", $"public, max-age={cacheMaxAgeOneWeek}");
}
});
app.UseAuthorization();
app.MapDefaultControllerRoute().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
위의 코드는 정적 파일을 1주일 동안 로컬 캐시에서 공개적으로 사용할 수 있도록 합니다.
정적 파일 권한 부여
ASP.NET Core 템플릿은 UseAuthorization을 호출하기 전에 MapStaticAssets를 호출합니다. 대부분의 앱은 이 패턴을 따릅니다. 정적 파일 미들웨어가 권한 부여 미들웨어 전에 호출되는 경우:
- 정적 파일에서 권한 부여 검사가 수행되지 않습니다.
wwwroot
아래에 있는 정적 파일과 같이 정적 파일 미들웨어가 제공하는 정적 파일은 공개적으로 액세스할 수 있습니다.
권한 부여를 기반으로 정적 파일을 제공하려면 다음을 수행합니다.
wwwroot
외부에 정적 파일을 저장합니다.UseAuthorization
을 호출한 후 경로를 지정하여UseStaticFiles
를 호출합니다.- 대체 권한 부여 정책을 설정합니다.
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.FileProviders;
using StaticFileAuth.Data;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
RequestPath = "/StaticFiles"
});
app.MapRazorPages();
app.Run();
위의 코드에서 대체 권한 부여 정책은 모든 사용자를 인증하도록 요구합니다. 자체 권한 부여 요구 사항을 지정하는 컨트롤러, Razor Pages 등과 같은 엔드포인트는 대체 권한 부여 정책을 사용하지 않습니다. 예를 들어 [AllowAnonymous]
또는 [Authorize(PolicyName="MyPolicy")]
가 있는 Razor Pages, 컨트롤러 또는 작업 메서드는 대체 권한 부여 정책이 아닌 적용된 권한 부여 특성을 사용합니다.
RequireAuthenticatedUser는 DenyAnonymousAuthorizationRequirement를 현재 인스턴스에 추가하여 현재 사용자가 인증될 것을 요구합니다.
기본 정적 파일 미들웨어(app.UseStaticFiles();
)가 UseAuthentication
전에 호출되기 때문에 wwwroot
아래의 정적 자산은 공개적으로 액세스할 수 있습니다. MyStaticFiles 폴더의 정적 자산에는 인증이 필요합니다. 샘플 코드는 이를 보여 줍니다.
권한 부여를 기반으로 파일을 제공하는 대체 방법은 다음과 같습니다.
파일을
wwwroot
외부의 정적 파일 미들웨어에 액세스할 수 있는 임의의 디렉터리에 저장합니다.권한 부여가 적용되는 작업 메서드를 통해 파일을 제공하고 FileResult 개체를 반환합니다.
[Authorize] public class BannerImageModel : PageModel { private readonly IWebHostEnvironment _env; public BannerImageModel(IWebHostEnvironment env) => _env = env; public PhysicalFileResult OnGet() { var filePath = Path.Combine( _env.ContentRootPath, "MyStaticFiles", "images", "red-rose.jpg"); return PhysicalFile(filePath, "image/jpeg"); } }
이전 방법을 사용하려면 파일당 페이지 또는 엔드포인트가 필요합니다. 다음 코드는 인증된 사용자를 위해 파일을 반환하거나 파일을 업로드합니다.
app.MapGet("/files/{fileName}", IResult (string fileName) =>
{
var filePath = GetOrCreateFilePath(fileName);
if (File.Exists(filePath))
{
return TypedResults.PhysicalFile(filePath, fileDownloadName: $"{fileName}");
}
return TypedResults.NotFound("No file found with the supplied file name");
})
.WithName("GetFileByName")
.RequireAuthorization("AuthenticatedUsers");
app.MapPost("/files",
async (IFormFile file, LinkGenerator linker, HttpContext context) =>
{
// Don't rely on the file.FileName as it is only metadata that can be
// manipulated by the end-user. See the `Utilities.IsFileValid` method that
// takes an IFormFile and validates its signature within the
// AllowedFileSignatures
var fileSaveName = Guid.NewGuid().ToString("N")
+ Path.GetExtension(file.FileName);
await SaveFileWithCustomFileName(file, fileSaveName);
context.Response.Headers.Append("Location",
linker.GetPathByName(context, "GetFileByName",
new { fileName = fileSaveName}));
return TypedResults.Ok("File Uploaded Successfully!");
})
.RequireAuthorization("AdminsOnly");
app.Run();
이전 샘플의 IFormFile은 업로드에 메모리 버퍼를 사용합니다. 대용량 파일 처리를 위해 스트리밍을 사용합니다. 스트리밍을 사용하여 대용량 파일 업로드를 참조 하세요.
전체 샘플은 StaticFileAuth GitHub 폴더를 참조하세요.
디렉터리 검색
디렉터리 검색을 통해 지정된 디렉터리 내에 디렉터리를 나열할 수 있습니다.
기본적으로 디렉터리 검색은 보안상의 이유로 사용하지 않도록 설정됩니다. 자세한 내용은 정적 파일의 보안 고려 사항을 참조하세요.
AddDirectoryBrowser 및 UseDirectoryBrowser를 통해 디렉터리 검색을 사용하도록 설정합니다.
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
builder.Services.AddDirectoryBrowser();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.MapStaticAssets();
var fileProvider = new PhysicalFileProvider(Path.Combine(builder.Environment.WebRootPath, "images"));
var requestPath = "/MyImages";
// Enable displaying browser links.
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = fileProvider,
RequestPath = requestPath
});
app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
FileProvider = fileProvider,
RequestPath = requestPath
});
app.UseAuthorization();
app.MapDefaultControllerRoute().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
위의 코드를 통해 URL https://<hostname>/MyImages
를 사용하여 각 파일 및 폴더에 대한 링크가 제공되는 wwwroot/images 폴더의 디렉터리 검색을 사용할 수 있습니다.
AddDirectoryBrowser
를 포함하여 HtmlEncoder디렉터리 검색 미들웨어에 필요한 서비스를 추가합니다. 이러한 서비스는 AddRazorPages와 같은 다른 호출에서 추가될 수 있지만 서비스가 모든 앱에 추가되도록 AddDirectoryBrowser
를 호출하는 것이 좋습니다.
기본 문서 제공
기본 페이지를 설정하면 방문자에게 사이트의 시작 지점이 제공됩니다. 요청 URL에 파일 이름을 포함하도록 요구하지 않고 wwwroot
에서 기본 파일을 제공하려면 UseDefaultFiles 메서드를 호출합니다.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseAuthorization();
app.MapDefaultControllerRoute().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
기본 파일을 제공하려면 UseStaticFiles
전에 UseDefaultFiles
를 먼저 호출해야 합니다. UseDefaultFiles
는 파일을 제공하지 않는 URL 재작성기입니다.
UseDefaultFiles
를 사용하면 wwwroot
의 폴더에 대한 요청이 다음을 검색합니다.
default.htm
default.html
index.htm
index.html
목록에서 찾은 첫 번째 파일이 요청에 파일 이름이 포함된 것처럼 제공됩니다. 브라우저 URL은 요청된 URI를 계속 반영합니다. 예를 들어 샘플 앱에서 제공하는 요청 https://localhost:<port>/def/
입니다 default.html
wwwroot/def
.
다음 코드는 기본 파일 이름을 다음과 같이 변경합니다 mydefault.html
.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
var options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("mydefault.html");
app.UseDefaultFiles(options);
app.UseStaticFiles();
app.UseAuthorization();
app.MapDefaultControllerRoute().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
기본 문서의 UseFileServer
UseFileServer는 UseStaticFiles
, UseDefaultFiles
및 선택적으로 UseDirectoryBrowser
의 기능을 병행합니다.
app.UseFileServer
를 호출하여 정적 파일 및 기본 파일을 제공할 수 있도록 합니다. 디렉터리 검색은 활성화되지 않습니다.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseFileServer();
app.UseAuthorization();
app.MapDefaultControllerRoute().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
다음 코드를 사용하면 정적 파일, 기본 파일 및 디렉터리 검색을 제공할 수 있습니다.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
builder.Services.AddDirectoryBrowser();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseFileServer(enableDirectoryBrowsing: true);
app.UseRouting();
app.UseAuthorization();
app.MapDefaultControllerRoute().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
다음 디렉터리 계층 구조를 고려해보세요.
wwwroot
css
images
js
MyStaticFiles
defaultFiles
default.html
image3.png
images
MyImage.jpg
다음 코드를 사용하면 MyStaticFiles
의 정적 파일, 기본 파일 및 디렉터리 검색을 제공할 수 있습니다.
using Microsoft.Extensions.FileProviders;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
builder.Services.AddDirectoryBrowser();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseFileServer(new FileServerOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
RequestPath = "/StaticFiles",
EnableDirectoryBrowsing = true
});
app.UseAuthorization();
app.MapDefaultControllerRoute().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
AddDirectoryBrowser는 EnableDirectoryBrowsing
속성 값이 true
인 경우 호출해야 합니다.
URL은 위의 파일 계층 구조 및 코드를 사용하여 다음과 같이 확인됩니다.
URI | 응답 |
---|---|
https://<hostname>/StaticFiles/images/MyImage.jpg |
MyStaticFiles/images/MyImage.jpg |
https://<hostname>/StaticFiles |
디렉터리 목록 |
https://<hostname>/StaticFiles/defaultFiles |
MyStaticFiles/defaultFiles/default.html |
https://<hostname>/StaticFiles/defaultFiles/image3.png |
MyStaticFiles/defaultFiles//image3.png |
MyStaticFiles 디렉터리에 기본 이름이 지정된 파일이 없는 경우 https://<hostname>/StaticFiles
는 클릭 가능한 링크와 함께 디렉터리 목록을 반환합니다.
UseDefaultFiles 및 UseDirectoryBrowser는 후행 /
가 없는 대상 URI에서 후행 /
가 있는 대상 URI로 클라이언트 쪽 리디렉션을 수행합니다. 예를 들어 https://<hostname>/StaticFiles
에서 https://<hostname>/StaticFiles/
로 리디렉션합니다. StaticFiles 디렉터리 내의 상대 URL은 후행 슬래시(/
)가 있어야 유효합니다. 단 DefaultFilesOptions의 RedirectToAppendTrailingSlash 옵션을 사용하는 경우에는 제외입니다.
FileExtensionContentTypeProvider
이 클래스에는 FileExtensionContentTypeProvider 파일 확장자를 MIME 콘텐츠 형식에 매핑하는 역할을 하는 Mappings 속성이 포함되어 있습니다. 다음 샘플에서는 여러 파일 확장명이 알려진 MIME 형식에 매핑됩니다. .rtf 확장명은 대체되며 .mp4는 제거됩니다.
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
// Set up custom content types - associating file extension to MIME type
var provider = new FileExtensionContentTypeProvider();
// Add new mappings
provider.Mappings[".myapp"] = "application/x-msdownload";
provider.Mappings[".htm3"] = "text/html";
provider.Mappings[".image"] = "image/png";
// Replace an existing mapping
provider.Mappings[".rtf"] = "application/x-msdownload";
// Remove MP4 videos.
provider.Mappings.Remove(".mp4");
app.UseStaticFiles(new StaticFileOptions
{
ContentTypeProvider = provider
});
app.UseAuthorization();
app.MapDefaultControllerRoute().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
MIME 콘텐츠 형식을 참조하세요.
비표준 콘텐츠 형식
정적 파일 미들웨어는 거의 400가지의 알려진 파일 콘텐츠 형식을 이해합니다. 사용자가 알 수 없는 파일 형식의 파일을 요청하는 경우 정적 파일 미들웨어가 해당 요청을 파이프라인의 다음 미들웨어로 전달합니다. 요청을 처리한 미들웨어가 없으면 ‘404 찾을 수 없음’ 응답이 반환됩니다. 디렉터리 찾아보기가 사용 가능한 경우 파일에 대한 링크가 디렉터리 목록에 표시됩니다.
다음 코드는 알 수 없는 형식 제공을 사용하도록 설정하고 알 수 없는 파일을 이미지로 렌더링합니다.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles(new StaticFileOptions
{
ServeUnknownFileTypes = true,
DefaultContentType = "image/png"
});
app.UseAuthorization();
app.MapDefaultControllerRoute().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
위의 코드를 사용하면 알 수 없는 콘텐츠 형식의 파일에 대한 요청은 이미지로 반환됩니다.
Warning
ServeUnknownFileTypes를 사용하도록 설정하는 것은 보안상 위험합니다. 기본적으로 비활성화되어 있으며 사용은 권장되지 않습니다. FileExtensionContentTypeProvider는 비표준 확장명을 가진 파일을 제공하는 것보다 안전한 대체 방법을 제공합니다.
여러 위치에서 파일 제공
/MyStaticFiles/image3.png
파일을 표시하는 다음 Razor 페이지를 고려하세요.
@page
<p> Test /MyStaticFiles/image3.png</p>
<img src="~/image3.png" class="img" asp-append-version="true" alt="Test">
UseStaticFiles
및 UseFileServer
는 기본적으로 wwwroot
를 가리키는 파일 공급자로 설정됩니다. 다른 위치에서 파일을 제공하기 위해 다른 파일 공급자와 UseStaticFiles
및 UseFileServer
의 추가 인스턴스를 제공할 수 있습니다. 다음 예제에서는 UseStaticFiles
를 두 번 호출하여 wwwroot
및 MyStaticFiles
모두에서 파일을 제공합니다.
app.UseStaticFiles();
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles"))
});
위의 코드를 사용하여 다음을 수행합니다.
/MyStaticFiles/image3.png
파일이 표시됩니다.- 태그 도우미 AppendVersion 가 에 의존WebRootFileProvider하기 때문에 이미지 태그 도우미가 적용되지 않습니다.
MyStaticFiles
폴더를 포함하도록WebRootFileProvider
가 업데이트되지 않았습니다.
다음 코드는 WebRootFileProvider
를 업데이트하여 이미지 태그 도우미가 버전을 제공할 수 있도록 합니다.
var webRootProvider = new PhysicalFileProvider(builder.Environment.WebRootPath);
var newPathProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles"));
var compositeProvider = new CompositeFileProvider(webRootProvider,
newPathProvider);
// Update the default provider.
app.Environment.WebRootFileProvider = compositeProvider;
app.MapStaticAssets();
참고 항목
이전 방법은 Pages 및 MVC 앱에 Razor 적용됩니다. s에 Blazor Web App적용되는 지침은 ASP.NET Core Blazor 정적 파일을 참조하세요.
정적 파일의 보안 고려 사항
Warning
UseDirectoryBrowser
비밀을 UseStaticFiles
누설할 수 있습니다. 프로덕션 환경에서는 디렉터리 검색을 비활성화하는 것이 좋습니다. UseStaticFiles
또는 UseDirectoryBrowser
를 통해 어떤 디렉터리가 활성화되었는지 주의 깊게 검토하세요. 전체 디렉터리와 해당 하위 디렉터리는 공개적으로 액세스할 수 있습니다. <content_root>/wwwroot
와 같은 전용 디렉터리에 공개적으로 제공하는 데 적합한 파일을 저장합니다. MVC 뷰, Razor Pages, 구성 파일 등과 해당 파일을 분리합니다.
로 노출되는
UseDirectoryBrowser
UseStaticFiles
콘텐츠의 URL이며MapStaticAssets
기본 파일 시스템의 대/소문자 민감도 및 문자 제한이 적용됩니다. 예를 들어 Windows는 대/소문자를 구분하지 않지만 macOS 및 Linux는 대/소문자를 구분합니다.IIS에서 호스팅되는 ASP.NET Core 앱은 ASP.NET Core 모듈을 사용하여 정적 파일 요청을 비롯한 모든 요청을 앱에 전달합니다. IIS 정적 파일 처리기는 사용되지 않으며 요청을 처리할 수 없습니다.
서버 또는 웹 사이트 수준에서 IIS 정적 파일 처리기를 제거하려면 IIS 관리자에서 다음 단계를 완료합니다.
- 모듈 기능으로 이동합니다.
- 목록에서 StaticFileModule을 선택합니다.
- 동작 사이드바에서 제거를 클릭합니다.
Warning
IIS 정적 파일 처리기를 사용하도록 설정되었으며 그리고 ASP.NET Core 모듈이 올바르게 구성되지 않은 경우, 정적 파일이 제공됩니다. 이는 예를 들어 web.config 파일이 배포되지 않는 경우에 발생합니다.
- 앱 프로젝트의 웹 루트 외부에 포함
.cs
및.cshtml
외부에 코드 파일을 배치합니다. 따라서 논리적 분리가 앱의 클라이언트 쪽 콘텐츠 및 서버 기반 코드 사이에 만들어집니다. 그러면 서버 쪽 코드가 유출되지 않습니다.
IWebHostEnvironment.WebRootPath를 업데이트하여 wwwroot 외부의 파일 제공
IWebHostEnvironment.WebRootPath가 wwwroot
이외의 폴더로 설정된 경우:
- 개발 환경에서는
wwwroot
및 업데이트된IWebHostEnvironment.WebRootPath
모두에서 찾은 정적 자산이wwwroot
에서 제공됩니다. - 개발 환경 이외의 환경에서는 중복된 정적 자산이 업데이트된
IWebHostEnvironment.WebRootPath
폴더에서 제공됩니다.
빈 웹 템플릿으로 만든 웹앱을 고려합니다.
wwwroot
및wwwroot-custom
의Index.html
파일 포함WebRootPath = "wwwroot-custom"
을 설정하는 다음과 같은 업데이트된Program.cs
파일 포함var builder = WebApplication.CreateBuilder(new WebApplicationOptions { Args = args, // Look for static files in "wwwroot-custom" WebRootPath = "wwwroot-custom" }); var app = builder.Build(); app.UseDefaultFiles(); app.MapStaticAssets(); app.Run();
위의 코드에서 /
에 대한 요청은
- 개발 환경에서는
wwwroot/Index.html
을 반환합니다. - 개발 환경 이외의 환경에서는
wwwroot-custom/Index.html
을 반환합니다.
wwwroot-custom
의 자산이 반환되도록 하려면 다음 방법 중 하나를 사용합니다.
wwwroot
에서 중복 명명된 자산을 삭제합니다.Properties/launchSettings.json
에서"ASPNETCORE_ENVIRONMENT"
를"Development"
이외의 값으로 설정합니다.프로젝트 파일에서
<StaticWebAssetsEnabled>false</StaticWebAssetsEnabled>
를 설정하여 정적 웹 자산을 완전히 사용하지 않도록 설정합니다. 경고, 정적 웹 자산을 사용하지 않도록 설정하면 Razor 클래스 라이브러리를 사용할 수 없습니다.프로젝트 파일에 다음 XML을 추가합니다.
<ItemGroup> <Content Remove="wwwroot\**" /> </ItemGroup>
다음 코드에서는 IWebHostEnvironment.WebRootPath
를 개발이 아닌 값으로 업데이트하여 중복 콘텐츠가 wwwroot
가 아니라 wwwroot-custom
에서 반환되도록 합니다.
var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
Args = args,
// Examine Hosting environment: logging value
EnvironmentName = Environments.Staging,
WebRootPath = "wwwroot-custom"
});
var app = builder.Build();
app.Logger.LogInformation("ASPNETCORE_ENVIRONMENT: {env}",
Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"));
app.Logger.LogInformation("app.Environment.IsDevelopment(): {env}",
app.Environment.IsDevelopment().ToString());
app.UseDefaultFiles();
app.MapStaticAssets();
app.Run();
추가 리소스
작성자: Rick Anderson
HTML, CSS, 이미지 및 JavaScript와 같은 정적 파일은 기본적으로 ASP.NET Core 앱이 클라이언트에 직접 제공하는 자산입니다.
정적 파일 제공
정적 파일은 프로젝트의 웹 루트 디렉터리 내에 저장됩니다. 기본 디렉터리는 {content root}/wwwroot
이지만, UseWebRoot 메서드를 통해 변경할 수 있습니다. 자세한 내용은 콘텐츠 루트 및 웹 루트를 참조하세요.
CreateBuilder 메서드는 콘텐츠 루트를 현재 디렉터리로 설정합니다.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
정적 파일은 웹 루트에 상대적인 경로를 통해 액세스할 수 있습니다. 예를 들어 웹 애플리케이션 프로젝트 템플릿에는 wwwroot
폴더 내에 여러 폴더가 포함되어 있습니다.
wwwroot
css
js
lib
wwwroot/images 폴더를 만들고 파일을 추가하는 것이 좋습니다wwwroot/images/MyImage.jpg
. images
폴더의 파일에 액세스하기 위한 URI 형식은 https://<hostname>/images/<image_file_name>
입니다. 예를 들어 https://localhost:5001/images/MyImage.jpg
웹 루트의 파일 제공
기본 웹앱 템플릿은 Program.cs
에서 UseStaticFiles 메서드를 호출하여 정적 파일을 제공할 수 있습니다.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
매개 변수가 없는 UseStaticFiles
메서드 오버로드는 웹 루트에 있는 파일을 제공 가능으로 표시합니다. 다음 태그 참조는 다음과 같습니다.wwwroot/images/MyImage.jpg
<img src="~/images/MyImage.jpg" class="img" alt="My image" />
위의 태그에서 물결표 문자(~
)는 웹 루트를 가리킵니다.
웹 루트 외부의 파일 제공
제공할 정적 파일이 웹 루트 외부에 있는 디렉터리 계층 구조를 고려해보세요.
wwwroot
css
images
js
MyStaticFiles
images
red-rose.jpg
요청은 정적 파일 미들웨어를 다음과 같이 구성하여 red-rose.jpg
파일에 액세스할 수 있습니다.
using Microsoft.Extensions.FileProviders;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
RequestPath = "/StaticFiles"
});
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
위의 코드에서 MyStaticFiles 디렉터리 계층 구조는 StaticFiles URI 세그먼트를 통해 공개적으로 노출됩니다. 파일을 제공하는 https://<hostname>/StaticFiles/images/red-rose.jpg
요청입니다 red-rose.jpg
.
다음 태그 참조는 다음과 같습니다.MyStaticFiles/images/red-rose.jpg
<img src="~/StaticFiles/images/red-rose.jpg" class="img" alt="A red rose" />
여러 위치에서 파일을 제공하려면 여러 위치에서 파일 제공을 참조하세요.
HTTP 응답 헤더 설정
StaticFileOptions 개체를 사용하여 HTTP 응답 헤더를 설정할 수 있습니다. 다음 코드는 웹 루트에서 제공되는 정적 파일을 구성하는 것 외에도 Cache-Control 헤더를 설정합니다.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
var cacheMaxAgeOneWeek = (60 * 60 * 24 * 7).ToString();
app.UseStaticFiles(new StaticFileOptions
{
OnPrepareResponse = ctx =>
{
ctx.Context.Response.Headers.Append(
"Cache-Control", $"public, max-age={cacheMaxAgeOneWeek}");
}
});
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
위의 코드는 로컬 캐시에서 정적 파일을 1주 동안(604,800초) 공개적으로 사용할 수 있도록 합니다.
정적 파일 권한 부여
ASP.NET Core 템플릿은 UseAuthorization을 호출하기 전에 UseStaticFiles를 호출합니다. 대부분의 앱은 이 패턴을 따릅니다. 정적 파일 미들웨어가 권한 부여 미들웨어 전에 호출되는 경우:
- 정적 파일에서 권한 부여 검사가 수행되지 않습니다.
wwwroot
아래에 있는 정적 파일과 같이 정적 파일 미들웨어가 제공하는 정적 파일은 공개적으로 액세스할 수 있습니다.
권한 부여를 기반으로 정적 파일을 제공하려면 다음을 수행합니다.
wwwroot
외부에 정적 파일을 저장합니다.UseAuthorization
을 호출한 후 경로를 지정하여UseStaticFiles
를 호출합니다.- 대체 권한 부여 정책을 설정합니다.
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.FileProviders;
using StaticFileAuth.Data;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
RequestPath = "/StaticFiles"
});
app.MapRazorPages();
app.Run();
위의 코드에서 대체 권한 부여 정책은 모든 사용자를 인증하도록 요구합니다. 자체 권한 부여 요구 사항을 지정하는 컨트롤러, Razor Pages 등과 같은 엔드포인트는 대체 권한 부여 정책을 사용하지 않습니다. 예를 들어 [AllowAnonymous]
또는 [Authorize(PolicyName="MyPolicy")]
가 있는 Razor Pages, 컨트롤러 또는 작업 메서드는 대체 권한 부여 정책이 아닌 적용된 권한 부여 특성을 사용합니다.
RequireAuthenticatedUser는 DenyAnonymousAuthorizationRequirement를 현재 인스턴스에 추가하여 현재 사용자가 인증될 것을 요구합니다.
기본 정적 파일 미들웨어(app.UseStaticFiles();
)가 UseAuthentication
전에 호출되기 때문에 wwwroot
아래의 정적 자산은 공개적으로 액세스할 수 있습니다. MyStaticFiles 폴더의 정적 자산에는 인증이 필요합니다. 샘플 코드는 이를 보여 줍니다.
권한 부여를 기반으로 파일을 제공하는 대체 방법은 다음과 같습니다.
파일을
wwwroot
외부의 정적 파일 미들웨어에 액세스할 수 있는 임의의 디렉터리에 저장합니다.권한 부여가 적용되는 작업 메서드를 통해 파일을 제공하고 FileResult 개체를 반환합니다.
[Authorize] public class BannerImageModel : PageModel { private readonly IWebHostEnvironment _env; public BannerImageModel(IWebHostEnvironment env) => _env = env; public PhysicalFileResult OnGet() { var filePath = Path.Combine( _env.ContentRootPath, "MyStaticFiles", "images", "red-rose.jpg"); return PhysicalFile(filePath, "image/jpeg"); } }
이전 방법을 사용하려면 파일당 페이지 또는 엔드포인트가 필요합니다. 다음 코드는 인증된 사용자를 위해 파일을 반환하거나 파일을 업로드합니다.
app.MapGet("/files/{fileName}", IResult (string fileName) =>
{
var filePath = GetOrCreateFilePath(fileName);
if (File.Exists(filePath))
{
return TypedResults.PhysicalFile(filePath, fileDownloadName: $"{fileName}");
}
return TypedResults.NotFound("No file found with the supplied file name");
})
.WithName("GetFileByName")
.RequireAuthorization("AuthenticatedUsers");
// IFormFile uses memory buffer for uploading. For handling large file use streaming instead.
// https://learn.microsoft.com/aspnet/core/mvc/models/file-uploads#upload-large-files-with-streaming
app.MapPost("/files", async (IFormFile file, LinkGenerator linker, HttpContext context) =>
{
// Don't rely on the file.FileName as it is only metadata that can be manipulated by the end-user
// Take a look at the `Utilities.IsFileValid` method that takes an IFormFile and validates its signature within the AllowedFileSignatures
var fileSaveName = Guid.NewGuid().ToString("N") + Path.GetExtension(file.FileName);
await SaveFileWithCustomFileName(file, fileSaveName);
context.Response.Headers.Append("Location", linker.GetPathByName(context, "GetFileByName", new { fileName = fileSaveName}));
return TypedResults.Ok("File Uploaded Successfully!");
})
.RequireAuthorization("AdminsOnly");
app.Run();
전체 샘플은 StaticFileAuth GitHub 폴더를 참조하세요.
디렉터리 검색
디렉터리 검색을 통해 지정된 디렉터리 내에 디렉터리를 나열할 수 있습니다.
기본적으로 디렉터리 검색은 보안상의 이유로 사용하지 않도록 설정됩니다. 자세한 내용은 정적 파일의 보안 고려 사항을 참조하세요.
AddDirectoryBrowser 및 UseDirectoryBrowser를 통해 디렉터리 검색을 사용하도록 설정합니다.
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
builder.Services.AddDirectoryBrowser();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
var fileProvider = new PhysicalFileProvider(Path.Combine(builder.Environment.WebRootPath, "images"));
var requestPath = "/MyImages";
// Enable displaying browser links.
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = fileProvider,
RequestPath = requestPath
});
app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
FileProvider = fileProvider,
RequestPath = requestPath
});
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
위의 코드를 통해 URL https://<hostname>/MyImages
를 사용하여 각 파일 및 폴더에 대한 링크가 제공되는 wwwroot/images 폴더의 디렉터리 검색을 사용할 수 있습니다.
AddDirectoryBrowser
를 포함하여 HtmlEncoder디렉터리 검색 미들웨어에 필요한 서비스를 추가합니다. 이러한 서비스는 AddRazorPages와 같은 다른 호출에서 추가될 수 있지만 서비스가 모든 앱에 추가되도록 AddDirectoryBrowser
를 호출하는 것이 좋습니다.
기본 문서 제공
기본 페이지를 설정하면 방문자에게 사이트의 시작 지점이 제공됩니다. 요청 URL에 파일 이름을 포함하도록 요구하지 않고 wwwroot
에서 기본 파일을 제공하려면 UseDefaultFiles 메서드를 호출합니다.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
기본 파일을 제공하려면 UseStaticFiles
전에 UseDefaultFiles
를 먼저 호출해야 합니다. UseDefaultFiles
는 파일을 제공하지 않는 URL 재작성기입니다.
UseDefaultFiles
를 사용하면 wwwroot
의 폴더에 대한 요청이 다음을 검색합니다.
default.htm
default.html
index.htm
index.html
목록에서 찾은 첫 번째 파일이 요청에 파일 이름이 포함된 것처럼 제공됩니다. 브라우저 URL은 요청된 URI를 계속 반영합니다.
다음 코드는 기본 파일 이름을 다음과 같이 변경합니다 mydefault.html
.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
var options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("mydefault.html");
app.UseDefaultFiles(options);
app.UseStaticFiles();
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
기본 문서의 UseFileServer
UseFileServer는 UseStaticFiles
, UseDefaultFiles
및 선택적으로 UseDirectoryBrowser
의 기능을 병행합니다.
app.UseFileServer
를 호출하여 정적 파일 및 기본 파일을 제공할 수 있도록 합니다. 디렉터리 검색은 활성화되지 않습니다.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseFileServer();
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
다음 코드를 사용하면 정적 파일, 기본 파일 및 디렉터리 검색을 제공할 수 있습니다.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
builder.Services.AddDirectoryBrowser();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseFileServer(enableDirectoryBrowsing: true);
app.UseRouting();
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
다음 디렉터리 계층 구조를 고려해보세요.
wwwroot
css
images
js
MyStaticFiles
images
MyImage.jpg
default.html
다음 코드를 사용하면 MyStaticFiles
의 정적 파일, 기본 파일 및 디렉터리 검색을 제공할 수 있습니다.
using Microsoft.Extensions.FileProviders;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
builder.Services.AddDirectoryBrowser();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseFileServer(new FileServerOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
RequestPath = "/StaticFiles",
EnableDirectoryBrowsing = true
});
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
AddDirectoryBrowser는 EnableDirectoryBrowsing
속성 값이 true
인 경우 호출해야 합니다.
URL은 위의 파일 계층 구조 및 코드를 사용하여 다음과 같이 확인됩니다.
URI | 응답 |
---|---|
https://<hostname>/StaticFiles/images/MyImage.jpg |
MyStaticFiles/images/MyImage.jpg |
https://<hostname>/StaticFiles |
MyStaticFiles/default.html |
MyStaticFiles 디렉터리에 기본 이름이 지정된 파일이 없는 경우 https://<hostname>/StaticFiles
는 클릭 가능한 링크와 함께 디렉터리 목록을 반환합니다.
UseDefaultFiles 및 UseDirectoryBrowser는 후행 /
가 없는 대상 URI에서 후행 /
가 있는 대상 URI로 클라이언트 쪽 리디렉션을 수행합니다. 예를 들어 https://<hostname>/StaticFiles
에서 https://<hostname>/StaticFiles/
로 리디렉션합니다. StaticFiles 디렉터리 내의 상대 URL은 후행 슬래시(/
)가 있어야 유효합니다. 단 DefaultFilesOptions의 RedirectToAppendTrailingSlash 옵션을 사용하는 경우에는 제외입니다.
FileExtensionContentTypeProvider
FileExtensionContentTypeProvider 클래스에는 MIME 콘텐츠 형식에 대한 파일 확장명 매핑 역할을 하는 Mappings
속성이 포함되어 있습니다. 다음 샘플에서는 여러 파일 확장명이 알려진 MIME 형식에 매핑됩니다. .rtf 확장명은 대체되며 .mp4는 제거됩니다.
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
// Set up custom content types - associating file extension to MIME type
var provider = new FileExtensionContentTypeProvider();
// Add new mappings
provider.Mappings[".myapp"] = "application/x-msdownload";
provider.Mappings[".htm3"] = "text/html";
provider.Mappings[".image"] = "image/png";
// Replace an existing mapping
provider.Mappings[".rtf"] = "application/x-msdownload";
// Remove MP4 videos.
provider.Mappings.Remove(".mp4");
app.UseStaticFiles(new StaticFileOptions
{
ContentTypeProvider = provider
});
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
MIME 콘텐츠 형식을 참조하세요.
비표준 콘텐츠 형식
정적 파일 미들웨어는 거의 400가지의 알려진 파일 콘텐츠 형식을 이해합니다. 사용자가 알 수 없는 파일 형식의 파일을 요청하는 경우 정적 파일 미들웨어가 해당 요청을 파이프라인의 다음 미들웨어로 전달합니다. 요청을 처리한 미들웨어가 없으면 ‘404 찾을 수 없음’ 응답이 반환됩니다. 디렉터리 찾아보기가 사용 가능한 경우 파일에 대한 링크가 디렉터리 목록에 표시됩니다.
다음 코드는 알 수 없는 형식 제공을 사용하도록 설정하고 알 수 없는 파일을 이미지로 렌더링합니다.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles(new StaticFileOptions
{
ServeUnknownFileTypes = true,
DefaultContentType = "image/png"
});
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
위의 코드를 사용하면 알 수 없는 콘텐츠 형식의 파일에 대한 요청은 이미지로 반환됩니다.
Warning
ServeUnknownFileTypes를 사용하도록 설정하는 것은 보안상 위험합니다. 기본적으로 비활성화되어 있으며 사용은 권장되지 않습니다. FileExtensionContentTypeProvider는 비표준 확장명을 가진 파일을 제공하는 것보다 안전한 대체 방법을 제공합니다.
여러 위치에서 파일 제공
/MyStaticFiles/image3.png
파일을 표시하는 다음 Razor 페이지를 고려하세요.
@page
<p> Test /MyStaticFiles/image3.png</p>
<img src="~/image3.png" class="img" asp-append-version="true" alt="Test">
UseStaticFiles
및 UseFileServer
는 기본적으로 wwwroot
를 가리키는 파일 공급자로 설정됩니다. 다른 위치에서 파일을 제공하기 위해 다른 파일 공급자와 UseStaticFiles
및 UseFileServer
의 추가 인스턴스를 제공할 수 있습니다. 다음 예제에서는 UseStaticFiles
를 두 번 호출하여 wwwroot
및 MyStaticFiles
모두에서 파일을 제공합니다.
app.UseStaticFiles(); // Serve files from wwwroot
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles"))
});
위의 코드를 사용하여 다음을 수행합니다.
/MyStaticFiles/image3.png
파일이 표시됩니다.- 태그 도우미 AppendVersion 가 에 의존WebRootFileProvider하기 때문에 이미지 태그 도우미가 적용되지 않습니다.
MyStaticFiles
폴더를 포함하도록WebRootFileProvider
가 업데이트되지 않았습니다.
다음 코드는 WebRootFileProvider
를 업데이트하여 이미지 태그 도우미가 버전을 제공할 수 있도록 합니다.
var webRootProvider = new PhysicalFileProvider(builder.Environment.WebRootPath);
var newPathProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles"));
var compositeProvider = new CompositeFileProvider(webRootProvider,
newPathProvider);
// Update the default provider.
app.Environment.WebRootFileProvider = compositeProvider;
app.UseStaticFiles();
참고 항목
이전 방법은 Pages 및 MVC 앱에 Razor 적용됩니다. s에 Blazor Web App적용되는 지침은 ASP.NET Core Blazor 정적 파일을 참조하세요.
정적 파일의 보안 고려 사항
Warning
UseDirectoryBrowser
및 UseStaticFiles
는 비밀 정보를 누출 할 수 있습니다. 프로덕션 환경에서는 디렉터리 검색을 비활성화하는 것이 좋습니다. UseStaticFiles
또는 UseDirectoryBrowser
를 통해 어떤 디렉터리가 활성화되었는지 주의 깊게 검토하세요. 전체 디렉터리와 해당 하위 디렉터리는 공개적으로 액세스할 수 있습니다. <content_root>/wwwroot
와 같은 전용 디렉터리에 공개적으로 제공하는 데 적합한 파일을 저장합니다. MVC 뷰, Razor Pages, 구성 파일 등과 해당 파일을 분리합니다.
UseDirectoryBrowser
및UseStaticFiles
로 노출된 콘텐츠에 대한 URL은 대/소문자 구분 및 기본 파일 시스템의 문자 제한이 적용됩니다. 예를 들어 Windows는 대/소문자를 구분하지 않지만 macOS 및 Linux는 대/소문자를 구분합니다.IIS에서 호스팅되는 ASP.NET Core 앱은 ASP.NET Core 모듈을 사용하여 정적 파일 요청을 비롯한 모든 요청을 앱에 전달합니다. IIS 정적 파일 처리기는 사용되지 않으며 요청을 처리할 수 없습니다.
서버 또는 웹 사이트 수준에서 IIS 정적 파일 처리기를 제거하려면 IIS 관리자에서 다음 단계를 완료합니다.
- 모듈 기능으로 이동합니다.
- 목록에서 StaticFileModule을 선택합니다.
- 동작 사이드바에서 제거를 클릭합니다.
Warning
IIS 정적 파일 처리기를 사용하도록 설정되었으며 그리고 ASP.NET Core 모듈이 올바르게 구성되지 않은 경우, 정적 파일이 제공됩니다. 이는 예를 들어 web.config 파일이 배포되지 않는 경우에 발생합니다.
- 앱 프로젝트의 웹 루트 외부에 포함
.cs
및.cshtml
외부에 코드 파일을 배치합니다. 따라서 논리적 분리가 앱의 클라이언트 쪽 콘텐츠 및 서버 기반 코드 사이에 만들어집니다. 그러면 서버 쪽 코드가 유출되지 않습니다.
IWebHostEnvironment.WebRootPath를 업데이트하여 wwwroot 외부의 파일 제공
IWebHostEnvironment.WebRootPath가 wwwroot
이외의 폴더로 설정된 경우:
- 개발 환경에서는
wwwroot
및 업데이트된IWebHostEnvironment.WebRootPath
모두에서 찾은 정적 자산이wwwroot
에서 제공됩니다. - 개발 환경 이외의 환경에서는 중복된 정적 자산이 업데이트된
IWebHostEnvironment.WebRootPath
폴더에서 제공됩니다.
빈 웹 템플릿으로 만든 웹앱을 고려합니다.
wwwroot
및wwwroot-custom
의Index.html
파일 포함WebRootPath = "wwwroot-custom"
을 설정하는 다음과 같은 업데이트된Program.cs
파일 포함var builder = WebApplication.CreateBuilder(new WebApplicationOptions { Args = args, // Look for static files in "wwwroot-custom" WebRootPath = "wwwroot-custom" }); var app = builder.Build(); app.UseDefaultFiles(); app.UseStaticFiles(); app.Run();
위의 코드에서 /
에 대한 요청은
- 개발 환경에서는
wwwroot/Index.html
을 반환합니다. - 개발 환경 이외의 환경에서는
wwwroot-custom/Index.html
을 반환합니다.
wwwroot-custom
의 자산이 반환되도록 하려면 다음 방법 중 하나를 사용합니다.
wwwroot
에서 중복 명명된 자산을 삭제합니다.Properties/launchSettings.json
에서"ASPNETCORE_ENVIRONMENT"
를"Development"
이외의 값으로 설정합니다.프로젝트 파일에서
<StaticWebAssetsEnabled>false</StaticWebAssetsEnabled>
를 설정하여 정적 웹 자산을 완전히 사용하지 않도록 설정합니다. 경고, 정적 웹 자산을 사용하지 않도록 설정하면 Razor 클래스 라이브러리를 사용할 수 없습니다.프로젝트 파일에 다음 JSON을 추가합니다.
<ItemGroup> <Content Remove="wwwroot\**" /> </ItemGroup>
다음 코드에서는 IWebHostEnvironment.WebRootPath
를 개발이 아닌 값으로 업데이트하여 중복 콘텐츠가 wwwroot
가 아니라 wwwroot-custom
에서 반환되도록 합니다.
var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
Args = args,
// Examine Hosting environment: logging value
EnvironmentName = Environments.Staging,
WebRootPath = "wwwroot-custom"
});
var app = builder.Build();
app.Logger.LogInformation("ASPNETCORE_ENVIRONMENT: {env}",
Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"));
app.Logger.LogInformation("app.Environment.IsDevelopment(): {env}",
app.Environment.IsDevelopment().ToString());
app.UseDefaultFiles();
app.UseStaticFiles();
app.Run();
추가 리소스
작성자: Rick Anderson 및 Kirk Larkin
HTML, CSS, 이미지 및 JavaScript와 같은 정적 파일은 기본적으로 ASP.NET Core 앱이 클라이언트에 직접 제공하는 자산입니다.
정적 파일 제공
정적 파일은 프로젝트의 웹 루트 디렉터리 내에 저장됩니다. 기본 디렉터리는 {content root}/wwwroot
이지만, UseWebRoot 메서드를 통해 변경할 수 있습니다. 자세한 내용은 콘텐츠 루트 및 웹 루트를 참조하세요.
CreateBuilder 메서드는 콘텐츠 루트를 현재 디렉터리로 설정합니다.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
정적 파일은 웹 루트에 상대적인 경로를 통해 액세스할 수 있습니다. 예를 들어 웹 애플리케이션 프로젝트 템플릿에는 wwwroot
폴더 내에 여러 폴더가 포함되어 있습니다.
wwwroot
css
js
lib
wwwroot/images 폴더를 만들고 파일을 추가하는 것이 좋습니다wwwroot/images/MyImage.jpg
. images
폴더의 파일에 액세스하기 위한 URI 형식은 https://<hostname>/images/<image_file_name>
입니다. 예를 들어 https://localhost:5001/images/MyImage.jpg
웹 루트의 파일 제공
기본 웹앱 템플릿은 Program.cs
에서 UseStaticFiles 메서드를 호출하여 정적 파일을 제공할 수 있습니다.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
매개 변수가 없는 UseStaticFiles
메서드 오버로드는 웹 루트에 있는 파일을 제공 가능으로 표시합니다. 다음 태그 참조는 다음과 같습니다.wwwroot/images/MyImage.jpg
<img src="~/images/MyImage.jpg" class="img" alt="My image" />
위의 태그에서 물결표 문자(~
)는 웹 루트를 가리킵니다.
웹 루트 외부의 파일 제공
제공할 정적 파일이 웹 루트 외부에 있는 디렉터리 계층 구조를 고려해보세요.
wwwroot
css
images
js
MyStaticFiles
images
red-rose.jpg
요청은 정적 파일 미들웨어를 다음과 같이 구성하여 red-rose.jpg
파일에 액세스할 수 있습니다.
using Microsoft.Extensions.FileProviders;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
RequestPath = "/StaticFiles"
});
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
위의 코드에서 MyStaticFiles 디렉터리 계층 구조는 StaticFiles URI 세그먼트를 통해 공개적으로 노출됩니다. 파일을 제공하는 https://<hostname>/StaticFiles/images/red-rose.jpg
요청입니다 red-rose.jpg
.
다음 태그 참조는 다음과 같습니다.MyStaticFiles/images/red-rose.jpg
<img src="~/StaticFiles/images/red-rose.jpg" class="img" alt="A red rose" />
여러 위치에서 파일을 제공하려면 여러 위치에서 파일 제공을 참조하세요.
HTTP 응답 헤더 설정
StaticFileOptions 개체를 사용하여 HTTP 응답 헤더를 설정할 수 있습니다. 다음 코드는 웹 루트에서 제공되는 정적 파일을 구성하는 것 외에도 Cache-Control 헤더를 설정합니다.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
var cacheMaxAgeOneWeek = (60 * 60 * 24 * 7).ToString();
app.UseStaticFiles(new StaticFileOptions
{
OnPrepareResponse = ctx =>
{
ctx.Context.Response.Headers.Append(
"Cache-Control", $"public, max-age={cacheMaxAgeOneWeek}");
}
});
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
위의 코드는 로컬 캐시에서 정적 파일을 1주 동안(604,800초) 공개적으로 사용할 수 있도록 합니다.
정적 파일 권한 부여
ASP.NET Core 템플릿은 UseAuthorization을 호출하기 전에 UseStaticFiles를 호출합니다. 대부분의 앱은 이 패턴을 따릅니다. 정적 파일 미들웨어가 권한 부여 미들웨어 전에 호출되는 경우:
- 정적 파일에서 권한 부여 검사가 수행되지 않습니다.
wwwroot
아래에 있는 정적 파일과 같이 정적 파일 미들웨어가 제공하는 정적 파일은 공개적으로 액세스할 수 있습니다.
권한 부여를 기반으로 정적 파일을 제공하려면 다음을 수행합니다.
wwwroot
외부에 정적 파일을 저장합니다.UseAuthorization
을 호출한 후 경로를 지정하여UseStaticFiles
를 호출합니다.- 대체 권한 부여 정책을 설정합니다.
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.FileProviders;
using StaticFileAuth.Data;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
RequestPath = "/StaticFiles"
});
app.MapRazorPages();
app.Run();
위의 코드에서 대체 권한 부여 정책은 모든 사용자를 인증하도록 요구합니다. 자체 권한 부여 요구 사항을 지정하는 컨트롤러, Razor Pages 등과 같은 엔드포인트는 대체 권한 부여 정책을 사용하지 않습니다. 예를 들어 [AllowAnonymous]
또는 [Authorize(PolicyName="MyPolicy")]
가 있는 Razor Pages, 컨트롤러 또는 작업 메서드는 대체 권한 부여 정책이 아닌 적용된 권한 부여 특성을 사용합니다.
RequireAuthenticatedUser는 DenyAnonymousAuthorizationRequirement를 현재 인스턴스에 추가하여 현재 사용자가 인증될 것을 요구합니다.
기본 정적 파일 미들웨어(app.UseStaticFiles();
)가 UseAuthentication
전에 호출되기 때문에 wwwroot
아래의 정적 자산은 공개적으로 액세스할 수 있습니다. MyStaticFiles 폴더의 정적 자산에는 인증이 필요합니다. 샘플 코드는 이를 보여 줍니다.
권한 부여를 기반으로 파일을 제공하는 대체 방법은 다음과 같습니다.
- 파일을
wwwroot
외부의 정적 파일 미들웨어에 액세스할 수 있는 임의의 디렉터리에 저장합니다. - 권한 부여가 적용되는 작업 메서드를 통해 파일을 제공하고 FileResult 개체를 반환합니다.
[Authorize]
public class BannerImageModel : PageModel
{
private readonly IWebHostEnvironment _env;
public BannerImageModel(IWebHostEnvironment env) =>
_env = env;
public PhysicalFileResult OnGet()
{
var filePath = Path.Combine(
_env.ContentRootPath, "MyStaticFiles", "images", "red-rose.jpg");
return PhysicalFile(filePath, "image/jpeg");
}
}
디렉터리 검색
디렉터리 검색을 통해 지정된 디렉터리 내에 디렉터리를 나열할 수 있습니다.
기본적으로 디렉터리 검색은 보안상의 이유로 사용하지 않도록 설정됩니다. 자세한 내용은 정적 파일의 보안 고려 사항을 참조하세요.
AddDirectoryBrowser 및 UseDirectoryBrowser를 통해 디렉터리 검색을 사용하도록 설정합니다.
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
builder.Services.AddDirectoryBrowser();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
var fileProvider = new PhysicalFileProvider(Path.Combine(builder.Environment.WebRootPath, "images"));
var requestPath = "/MyImages";
// Enable displaying browser links.
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = fileProvider,
RequestPath = requestPath
});
app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
FileProvider = fileProvider,
RequestPath = requestPath
});
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
위의 코드를 통해 URL https://<hostname>/MyImages
를 사용하여 각 파일 및 폴더에 대한 링크가 제공되는 wwwroot/images 폴더의 디렉터리 검색을 사용할 수 있습니다.
AddDirectoryBrowser
를 포함하여 HtmlEncoder디렉터리 검색 미들웨어에 필요한 서비스를 추가합니다. 이러한 서비스는 AddRazorPages와 같은 다른 호출에서 추가될 수 있지만 서비스가 모든 앱에 추가되도록 AddDirectoryBrowser
를 호출하는 것이 좋습니다.
기본 문서 제공
기본 페이지를 설정하면 방문자에게 사이트의 시작 지점이 제공됩니다. 요청 URL에 파일 이름을 포함하도록 요구하지 않고 wwwroot
에서 기본 파일을 제공하려면 UseDefaultFiles 메서드를 호출합니다.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
기본 파일을 제공하려면 UseStaticFiles
전에 UseDefaultFiles
를 먼저 호출해야 합니다. UseDefaultFiles
는 파일을 제공하지 않는 URL 재작성기입니다.
UseDefaultFiles
를 사용하면 wwwroot
의 폴더에 대한 요청이 다음을 검색합니다.
default.htm
default.html
index.htm
index.html
목록에서 찾은 첫 번째 파일이 요청에 파일 이름이 포함된 것처럼 제공됩니다. 브라우저 URL은 요청된 URI를 계속 반영합니다.
다음 코드는 기본 파일 이름을 다음과 같이 변경합니다 mydefault.html
.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
var options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("mydefault.html");
app.UseDefaultFiles(options);
app.UseStaticFiles();
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
기본 문서의 UseFileServer
UseFileServer는 UseStaticFiles
, UseDefaultFiles
및 선택적으로 UseDirectoryBrowser
의 기능을 병행합니다.
app.UseFileServer
를 호출하여 정적 파일 및 기본 파일을 제공할 수 있도록 합니다. 디렉터리 검색은 활성화되지 않습니다.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseFileServer();
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
다음 코드를 사용하면 정적 파일, 기본 파일 및 디렉터리 검색을 제공할 수 있습니다.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
builder.Services.AddDirectoryBrowser();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseFileServer(enableDirectoryBrowsing: true);
app.UseRouting();
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
다음 디렉터리 계층 구조를 고려해보세요.
wwwroot
css
images
js
MyStaticFiles
images
MyImage.jpg
default.html
다음 코드를 사용하면 MyStaticFiles
의 정적 파일, 기본 파일 및 디렉터리 검색을 제공할 수 있습니다.
using Microsoft.Extensions.FileProviders;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
builder.Services.AddDirectoryBrowser();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseFileServer(new FileServerOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
RequestPath = "/StaticFiles",
EnableDirectoryBrowsing = true
});
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
AddDirectoryBrowser는 EnableDirectoryBrowsing
속성 값이 true
인 경우 호출해야 합니다.
URL은 위의 파일 계층 구조 및 코드를 사용하여 다음과 같이 확인됩니다.
URI | 응답 |
---|---|
https://<hostname>/StaticFiles/images/MyImage.jpg |
MyStaticFiles/images/MyImage.jpg |
https://<hostname>/StaticFiles |
MyStaticFiles/default.html |
MyStaticFiles 디렉터리에 기본 이름이 지정된 파일이 없는 경우 https://<hostname>/StaticFiles
는 클릭 가능한 링크와 함께 디렉터리 목록을 반환합니다.
UseDefaultFiles 및 UseDirectoryBrowser는 후행 /
가 없는 대상 URI에서 후행 /
가 있는 대상 URI로 클라이언트 쪽 리디렉션을 수행합니다. 예를 들어 https://<hostname>/StaticFiles
에서 https://<hostname>/StaticFiles/
로 리디렉션합니다. StaticFiles 디렉터리 내의 상대 URL은 후행 슬래시(/
)가 있어야 유효합니다. 단 DefaultFilesOptions의 RedirectToAppendTrailingSlash 옵션을 사용하는 경우에는 제외입니다.
FileExtensionContentTypeProvider
FileExtensionContentTypeProvider 클래스에는 MIME 콘텐츠 형식에 대한 파일 확장명 매핑 역할을 하는 Mappings
속성이 포함되어 있습니다. 다음 샘플에서는 여러 파일 확장명이 알려진 MIME 형식에 매핑됩니다. .rtf 확장명은 대체되며 .mp4는 제거됩니다.
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
// Set up custom content types - associating file extension to MIME type
var provider = new FileExtensionContentTypeProvider();
// Add new mappings
provider.Mappings[".myapp"] = "application/x-msdownload";
provider.Mappings[".htm3"] = "text/html";
provider.Mappings[".image"] = "image/png";
// Replace an existing mapping
provider.Mappings[".rtf"] = "application/x-msdownload";
// Remove MP4 videos.
provider.Mappings.Remove(".mp4");
app.UseStaticFiles(new StaticFileOptions
{
ContentTypeProvider = provider
});
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
MIME 콘텐츠 형식을 참조하세요.
비표준 콘텐츠 형식
정적 파일 미들웨어는 거의 400가지의 알려진 파일 콘텐츠 형식을 이해합니다. 사용자가 알 수 없는 파일 형식의 파일을 요청하는 경우 정적 파일 미들웨어가 해당 요청을 파이프라인의 다음 미들웨어로 전달합니다. 요청을 처리한 미들웨어가 없으면 ‘404 찾을 수 없음’ 응답이 반환됩니다. 디렉터리 찾아보기가 사용 가능한 경우 파일에 대한 링크가 디렉터리 목록에 표시됩니다.
다음 코드는 알 수 없는 형식 제공을 사용하도록 설정하고 알 수 없는 파일을 이미지로 렌더링합니다.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles(new StaticFileOptions
{
ServeUnknownFileTypes = true,
DefaultContentType = "image/png"
});
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
위의 코드를 사용하면 알 수 없는 콘텐츠 형식의 파일에 대한 요청은 이미지로 반환됩니다.
Warning
ServeUnknownFileTypes를 사용하도록 설정하는 것은 보안상 위험합니다. 기본적으로 비활성화되어 있으며 사용은 권장되지 않습니다. FileExtensionContentTypeProvider는 비표준 확장명을 가진 파일을 제공하는 것보다 안전한 대체 방법을 제공합니다.
여러 위치에서 파일 제공
/MyStaticFiles/image3.png
파일을 표시하는 다음 Razor 페이지를 고려하세요.
@page
<p> Test /MyStaticFiles/image3.png</p>
<img src="~/image3.png" class="img" asp-append-version="true" alt="Test">
UseStaticFiles
및 UseFileServer
는 기본적으로 wwwroot
를 가리키는 파일 공급자로 설정됩니다. 다른 위치에서 파일을 제공하기 위해 다른 파일 공급자와 UseStaticFiles
및 UseFileServer
의 추가 인스턴스를 제공할 수 있습니다. 다음 예제에서는 UseStaticFiles
를 두 번 호출하여 wwwroot
및 MyStaticFiles
모두에서 파일을 제공합니다.
app.UseStaticFiles(); // Serve files from wwwroot
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles"))
});
위의 코드를 사용하여 다음을 수행합니다.
/MyStaticFiles/image3.png
파일이 표시됩니다.- 태그 도우미 AppendVersion 가 에 의존WebRootFileProvider하기 때문에 이미지 태그 도우미가 적용되지 않습니다.
MyStaticFiles
폴더를 포함하도록WebRootFileProvider
가 업데이트되지 않았습니다.
다음 코드는 WebRootFileProvider
를 업데이트하여 이미지 태그 도우미가 버전을 제공할 수 있도록 합니다.
var webRootProvider = new PhysicalFileProvider(builder.Environment.WebRootPath);
var newPathProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles"));
var compositeProvider = new CompositeFileProvider(webRootProvider,
newPathProvider);
// Update the default provider.
app.Environment.WebRootFileProvider = compositeProvider;
app.UseStaticFiles();
정적 파일의 보안 고려 사항
Warning
UseDirectoryBrowser
및 UseStaticFiles
는 비밀 정보를 누출 할 수 있습니다. 프로덕션 환경에서는 디렉터리 검색을 비활성화하는 것이 좋습니다. UseStaticFiles
또는 UseDirectoryBrowser
를 통해 어떤 디렉터리가 활성화되었는지 주의 깊게 검토하세요. 전체 디렉터리와 해당 하위 디렉터리는 공개적으로 액세스할 수 있습니다. <content_root>/wwwroot
와 같은 전용 디렉터리에 공개적으로 제공하는 데 적합한 파일을 저장합니다. MVC 뷰, Razor Pages, 구성 파일 등과 해당 파일을 분리합니다.
UseDirectoryBrowser
및UseStaticFiles
로 노출된 콘텐츠에 대한 URL은 대/소문자 구분 및 기본 파일 시스템의 문자 제한이 적용됩니다. 예를 들어 Windows는 대/소문자를 구분하지 않지만 macOS 및 Linux는 대/소문자를 구분합니다.IIS에서 호스팅되는 ASP.NET Core 앱은 ASP.NET Core 모듈을 사용하여 정적 파일 요청을 비롯한 모든 요청을 앱에 전달합니다. IIS 정적 파일 처리기는 사용되지 않으며 요청을 처리할 수 없습니다.
서버 또는 웹 사이트 수준에서 IIS 정적 파일 처리기를 제거하려면 IIS 관리자에서 다음 단계를 완료합니다.
- 모듈 기능으로 이동합니다.
- 목록에서 StaticFileModule을 선택합니다.
- 동작 사이드바에서 제거를 클릭합니다.
Warning
IIS 정적 파일 처리기를 사용하도록 설정되었으며 그리고 ASP.NET Core 모듈이 올바르게 구성되지 않은 경우, 정적 파일이 제공됩니다. 이는 예를 들어 web.config 파일이 배포되지 않는 경우에 발생합니다.
- 앱 프로젝트의 웹 루트 외부에 포함
.cs
및.cshtml
외부에 코드 파일을 배치합니다. 따라서 논리적 분리가 앱의 클라이언트 쪽 콘텐츠 및 서버 기반 코드 사이에 만들어집니다. 그러면 서버 쪽 코드가 유출되지 않습니다.
IWebHostEnvironment.WebRootPath를 업데이트하여 wwwroot 외부의 파일 제공
IWebHostEnvironment.WebRootPath가 wwwroot
이외의 폴더로 설정된 경우:
- 개발 환경에서는
wwwroot
및 업데이트된IWebHostEnvironment.WebRootPath
모두에서 찾은 정적 자산이wwwroot
에서 제공됩니다. - 개발 환경 이외의 환경에서는 중복된 정적 자산이 업데이트된
IWebHostEnvironment.WebRootPath
폴더에서 제공됩니다.
빈 웹 템플릿으로 만든 웹앱을 고려합니다.
wwwroot
및wwwroot-custom
의Index.html
파일 포함WebRootPath = "wwwroot-custom"
을 설정하는 다음과 같은 업데이트된Program.cs
파일 포함var builder = WebApplication.CreateBuilder(new WebApplicationOptions { Args = args, // Look for static files in "wwwroot-custom" WebRootPath = "wwwroot-custom" }); var app = builder.Build(); app.UseDefaultFiles(); app.UseStaticFiles(); app.Run();
위의 코드에서 /
에 대한 요청은
- 개발 환경에서는
wwwroot/Index.html
을 반환합니다. - 개발 환경 이외의 환경에서는
wwwroot-custom/Index.html
을 반환합니다.
wwwroot-custom
의 자산이 반환되도록 하려면 다음 방법 중 하나를 사용합니다.
wwwroot
에서 중복 명명된 자산을 삭제합니다.Properties/launchSettings.json
에서"ASPNETCORE_ENVIRONMENT"
를"Development"
이외의 값으로 설정합니다.프로젝트 파일에서
<StaticWebAssetsEnabled>false</StaticWebAssetsEnabled>
를 설정하여 정적 웹 자산을 완전히 사용하지 않도록 설정합니다. 경고, 정적 웹 자산을 사용하지 않도록 설정하면 Razor 클래스 라이브러리를 사용할 수 없습니다.프로젝트 파일에 다음 JSON을 추가합니다.
<ItemGroup> <Content Remove="wwwroot\**" /> </ItemGroup>
다음 코드에서는 IWebHostEnvironment.WebRootPath
를 개발이 아닌 값으로 업데이트하여 중복 콘텐츠가 wwwroot
가 아니라 wwwroot-custom
에서 반환되도록 합니다.
var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
Args = args,
// Examine Hosting environment: logging value
EnvironmentName = Environments.Staging,
WebRootPath = "wwwroot-custom"
});
var app = builder.Build();
app.Logger.LogInformation("ASPNETCORE_ENVIRONMENT: {env}",
Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"));
app.Logger.LogInformation("app.Environment.IsDevelopment(): {env}",
app.Environment.IsDevelopment().ToString());
app.UseDefaultFiles();
app.UseStaticFiles();
app.Run();
추가 리소스
작성자: Rick Anderson 및 Kirk Larkin
HTML, CSS, 이미지 및 JavaScript와 같은 정적 파일은 기본적으로 ASP.NET Core 앱이 클라이언트에 직접 제공하는 자산입니다.
정적 파일 제공
정적 파일은 프로젝트의 웹 루트 디렉터리 내에 저장됩니다. 기본 디렉터리는 {content root}/wwwroot
이지만, UseWebRoot 메서드를 통해 변경할 수 있습니다. 자세한 내용은 콘텐츠 루트 및 웹 루트를 참조하세요.
CreateDefaultBuilder 메서드는 콘텐츠 루트를 현재 디렉터리로 설정합니다.
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
위의 코드는 웹앱 템플릿을 사용하여 만들었습니다.
정적 파일은 웹 루트에 상대적인 경로를 통해 액세스할 수 있습니다. 예를 들어 웹 애플리케이션 프로젝트 템플릿에는 wwwroot
폴더 내에 여러 폴더가 포함되어 있습니다.
wwwroot
css
js
lib
wwwroot/images 폴더를 만들고 파일을 추가하는 것이 좋습니다wwwroot/images/MyImage.jpg
. images
폴더의 파일에 액세스하기 위한 URI 형식은 https://<hostname>/images/<image_file_name>
입니다. 예를 들어 https://localhost:5001/images/MyImage.jpg
웹 루트의 파일 제공
기본 웹앱 템플릿은 Startup.Configure
에서 UseStaticFiles 메서드를 호출하여 정적 파일을 제공할 수 있습니다.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
매개 변수가 없는 UseStaticFiles
메서드 오버로드는 웹 루트에 있는 파일을 제공 가능으로 표시합니다. 다음 태그 참조는 다음과 같습니다.wwwroot/images/MyImage.jpg
<img src="~/images/MyImage.jpg" class="img" alt="My image" />
위의 코드에서 물결표 문자 ~/
는 웹 루트를 가리킵니다.
웹 루트 외부의 파일 제공
제공할 정적 파일이 웹 루트 외부에 있는 디렉터리 계층 구조를 고려해보세요.
wwwroot
css
images
js
MyStaticFiles
images
red-rose.jpg
요청은 정적 파일 미들웨어를 다음과 같이 구성하여 red-rose.jpg
파일에 액세스할 수 있습니다.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
// using Microsoft.Extensions.FileProviders;
// using System.IO;
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.ContentRootPath, "MyStaticFiles")),
RequestPath = "/StaticFiles"
});
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
위의 코드에서 MyStaticFiles 디렉터리 계층 구조는 StaticFiles URI 세그먼트를 통해 공개적으로 노출됩니다. 파일을 제공하는 https://<hostname>/StaticFiles/images/red-rose.jpg
요청입니다 red-rose.jpg
.
다음 태그 참조는 다음과 같습니다.MyStaticFiles/images/red-rose.jpg
<img src="~/StaticFiles/images/red-rose.jpg" class="img" alt="A red rose" />
HTTP 응답 헤더 설정
StaticFileOptions 개체를 사용하여 HTTP 응답 헤더를 설정할 수 있습니다. 다음 코드는 웹 루트에서 제공되는 정적 파일을 구성하는 것 외에도 Cache-Control
헤더를 설정합니다.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
const string cacheMaxAge = "604800";
app.UseStaticFiles(new StaticFileOptions
{
OnPrepareResponse = ctx =>
{
// using Microsoft.AspNetCore.Http;
ctx.Context.Response.Headers.Append(
"Cache-Control", $"public, max-age={cacheMaxAge}");
}
});
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
위의 코드는 최대 사용 기간을 604,800초(7일)로 설정합니다.
정적 파일 권한 부여
ASP.NET Core 템플릿은 UseAuthorization을 호출하기 전에 UseStaticFiles를 호출합니다. 대부분의 앱은 이 패턴을 따릅니다. 정적 파일 미들웨어가 권한 부여 미들웨어 전에 호출되는 경우:
- 정적 파일에서 권한 부여 검사가 수행되지 않습니다.
wwwroot
아래에 있는 정적 파일과 같이 정적 파일 미들웨어가 제공하는 정적 파일은 공개적으로 액세스할 수 있습니다.
권한 부여를 기반으로 정적 파일을 제공하려면 다음을 수행합니다.
wwwroot
외부에 정적 파일을 저장합니다.UseAuthorization
을 호출한 후 경로를 지정하여UseStaticFiles
를 호출합니다.- 대체 권한 부여 정책을 설정합니다.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
// wwwroot css, JavaScript, and images don't require authentication.
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.ContentRootPath, "MyStaticFiles")),
RequestPath = "/StaticFiles"
});
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddRazorPages();
services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});
}
// Remaining code ommitted for brevity.
위의 코드에서 대체 권한 부여 정책은 모든 사용자를 인증하도록 요구합니다. 자체 권한 부여 요구 사항을 지정하는 컨트롤러, Razor Pages 등과 같은 엔드포인트는 대체 권한 부여 정책을 사용하지 않습니다. 예를 들어 [AllowAnonymous]
또는 [Authorize(PolicyName="MyPolicy")]
가 있는 Razor Pages, 컨트롤러 또는 작업 메서드는 대체 권한 부여 정책이 아닌 적용된 권한 부여 특성을 사용합니다.
RequireAuthenticatedUser는 DenyAnonymousAuthorizationRequirement를 현재 인스턴스에 추가하여 현재 사용자가 인증될 것을 요구합니다.
기본 정적 파일 미들웨어(app.UseStaticFiles();
)가 UseAuthentication
전에 호출되기 때문에 wwwroot
아래의 정적 자산은 공개적으로 액세스할 수 있습니다. MyStaticFiles 폴더의 정적 자산에는 인증이 필요합니다. 샘플 코드는 이를 보여 줍니다.
권한 부여를 기반으로 파일을 제공하는 대체 방법은 다음과 같습니다.
- 파일을
wwwroot
외부의 정적 파일 미들웨어에 액세스할 수 있는 임의의 디렉터리에 저장합니다. - 권한 부여가 적용되는 작업 메서드를 통해 파일을 제공하고 FileResult 개체를 반환합니다.
[Authorize]
public IActionResult BannerImage()
{
var filePath = Path.Combine(
_env.ContentRootPath, "MyStaticFiles", "images", "red-rose.jpg");
return PhysicalFile(filePath, "image/jpeg");
}
디렉터리 검색
디렉터리 검색을 통해 지정된 디렉터리 내에 디렉터리를 나열할 수 있습니다.
기본적으로 디렉터리 검색은 보안상의 이유로 사용하지 않도록 설정됩니다. 자세한 내용은 정적 파일의 보안 고려 사항을 참조하세요.
다음을 통해 디렉터리 검색을 사용하도록 설정합니다.
Startup.ConfigureServices
의 AddDirectoryBrowser.Startup.Configure
의 UseDirectoryBrowser.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddDirectoryBrowser();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
// using Microsoft.Extensions.FileProviders;
// using System.IO;
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.WebRootPath, "images")),
RequestPath = "/MyImages"
});
app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.WebRootPath, "images")),
RequestPath = "/MyImages"
});
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
위의 코드를 통해 URL https://<hostname>/MyImages
를 사용하여 각 파일 및 폴더에 대한 링크가 제공되는 wwwroot/images 폴더의 디렉터리 검색을 사용할 수 있습니다.
기본 문서 제공
기본 페이지를 설정하면 방문자에게 사이트의 시작 지점이 제공됩니다. 요청 URL에 파일 이름을 포함하도록 요구하지 않고 wwwroot
에서 기본 파일을 제공하려면 UseDefaultFiles 메서드를 호출합니다.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
기본 파일을 제공하려면 UseStaticFiles
전에 UseDefaultFiles
를 먼저 호출해야 합니다. UseDefaultFiles
는 파일을 제공하지 않는 URL 재작성기입니다.
UseDefaultFiles
를 사용하면 wwwroot
의 폴더에 대한 요청이 다음을 검색합니다.
default.htm
default.html
index.htm
index.html
목록에서 찾은 첫 번째 파일이 요청에 파일 이름이 포함된 것처럼 제공됩니다. 브라우저 URL은 요청된 URI를 계속 반영합니다.
다음 코드는 기본 파일 이름을 다음과 같이 변경합니다 mydefault.html
.
var options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("mydefault.html");
app.UseDefaultFiles(options);
app.UseStaticFiles();
다음 코드는 위의 코드와 함께 Startup.Configure
를 보여 줍니다.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
var options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("mydefault.html");
app.UseDefaultFiles(options);
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
기본 문서의 UseFileServer
UseFileServer는 UseStaticFiles
, UseDefaultFiles
및 선택적으로 UseDirectoryBrowser
의 기능을 병행합니다.
app.UseFileServer
를 호출하여 정적 파일 및 기본 파일을 제공할 수 있도록 합니다. 디렉터리 검색은 활성화되지 않습니다. 다음 코드는 UseFileServer
와 함께 Startup.Configure
를 보여 줍니다.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseFileServer();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
다음 코드를 사용하면 정적 파일, 기본 파일 및 디렉터리 검색을 제공할 수 있습니다.
app.UseFileServer(enableDirectoryBrowsing: true);
다음 코드는 위의 코드와 함께 Startup.Configure
를 보여 줍니다.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseFileServer(enableDirectoryBrowsing: true);
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
다음 디렉터리 계층 구조를 고려해보세요.
wwwroot
css
images
js
MyStaticFiles
images
MyImage.jpg
default.html
다음 코드를 사용하면 MyStaticFiles
의 정적 파일, 기본 파일 및 디렉터리 검색을 제공할 수 있습니다.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddDirectoryBrowser();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles(); // For the wwwroot folder.
// using Microsoft.Extensions.FileProviders;
// using System.IO;
app.UseFileServer(new FileServerOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.ContentRootPath, "MyStaticFiles")),
RequestPath = "/StaticFiles",
EnableDirectoryBrowsing = true
});
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
AddDirectoryBrowser는 EnableDirectoryBrowsing
속성 값이 true
인 경우 호출해야 합니다.
URL은 파일 계층 구조 및 이전 코드를 사용하여 다음과 같이 확인합니다.
URI | 응답 |
---|---|
https://<hostname>/StaticFiles/images/MyImage.jpg |
MyStaticFiles/images/MyImage.jpg |
https://<hostname>/StaticFiles |
MyStaticFiles/default.html |
MyStaticFiles 디렉터리에 기본 이름이 지정된 파일이 없는 경우 https://<hostname>/StaticFiles
는 클릭 가능한 링크와 함께 디렉터리 목록을 반환합니다.
UseDefaultFiles 및 UseDirectoryBrowser는 후행 /
가 없는 대상 URI에서 후행 /
가 있는 대상 URI로 클라이언트 쪽 리디렉션을 수행합니다. 예를 들어 https://<hostname>/StaticFiles
에서 https://<hostname>/StaticFiles/
로 리디렉션합니다. StaticFiles 디렉터리 내의 상대 URL은 후행 슬래시(/
)가 있어야 유효합니다.
FileExtensionContentTypeProvider
FileExtensionContentTypeProvider 클래스에는 MIME 콘텐츠 형식에 대한 파일 확장명 매핑 역할을 하는 Mappings
속성이 포함되어 있습니다. 다음 샘플에서는 여러 파일 확장명이 알려진 MIME 형식에 매핑됩니다. .rtf 확장명은 대체되며 .mp4는 제거됩니다.
// using Microsoft.AspNetCore.StaticFiles;
// using Microsoft.Extensions.FileProviders;
// using System.IO;
// Set up custom content types - associating file extension to MIME type
var provider = new FileExtensionContentTypeProvider();
// Add new mappings
provider.Mappings[".myapp"] = "application/x-msdownload";
provider.Mappings[".htm3"] = "text/html";
provider.Mappings[".image"] = "image/png";
// Replace an existing mapping
provider.Mappings[".rtf"] = "application/x-msdownload";
// Remove MP4 videos.
provider.Mappings.Remove(".mp4");
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.WebRootPath, "images")),
RequestPath = "/MyImages",
ContentTypeProvider = provider
});
app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.WebRootPath, "images")),
RequestPath = "/MyImages"
});
다음 코드는 위의 코드와 함께 Startup.Configure
를 보여 줍니다.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
// using Microsoft.AspNetCore.StaticFiles;
// using Microsoft.Extensions.FileProviders;
// using System.IO;
// Set up custom content types - associating file extension to MIME type
var provider = new FileExtensionContentTypeProvider();
// Add new mappings
provider.Mappings[".myapp"] = "application/x-msdownload";
provider.Mappings[".htm3"] = "text/html";
provider.Mappings[".image"] = "image/png";
// Replace an existing mapping
provider.Mappings[".rtf"] = "application/x-msdownload";
// Remove MP4 videos.
provider.Mappings.Remove(".mp4");
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.WebRootPath, "images")),
RequestPath = "/MyImages",
ContentTypeProvider = provider
});
app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.WebRootPath, "images")),
RequestPath = "/MyImages"
});
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
MIME 콘텐츠 형식을 참조하세요.
비표준 콘텐츠 형식
정적 파일 미들웨어는 거의 400가지의 알려진 파일 콘텐츠 형식을 이해합니다. 사용자가 알 수 없는 파일 형식의 파일을 요청하는 경우 정적 파일 미들웨어가 해당 요청을 파이프라인의 다음 미들웨어로 전달합니다. 요청을 처리한 미들웨어가 없으면 ‘404 찾을 수 없음’ 응답이 반환됩니다. 디렉터리 찾아보기가 사용 가능한 경우 파일에 대한 링크가 디렉터리 목록에 표시됩니다.
다음 코드는 알 수 없는 형식 제공을 사용하도록 설정하고 알 수 없는 파일을 이미지로 렌더링합니다.
app.UseStaticFiles(new StaticFileOptions
{
ServeUnknownFileTypes = true,
DefaultContentType = "image/png"
});
다음 코드는 위의 코드와 함께 Startup.Configure
를 보여 줍니다.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles(new StaticFileOptions
{
ServeUnknownFileTypes = true,
DefaultContentType = "image/png"
});
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
위의 코드를 사용하면 알 수 없는 콘텐츠 형식의 파일에 대한 요청은 이미지로 반환됩니다.
Warning
ServeUnknownFileTypes를 사용하도록 설정하는 것은 보안상 위험합니다. 기본적으로 비활성화되어 있으며 사용은 권장되지 않습니다. FileExtensionContentTypeProvider는 비표준 확장명을 가진 파일을 제공하는 것보다 안전한 대체 방법을 제공합니다.
여러 위치에서 파일 제공
UseStaticFiles
및 UseFileServer
는 기본적으로 wwwroot
를 가리키는 파일 공급자로 설정됩니다. 다른 위치에서 파일을 제공하기 위해 다른 파일 공급자와 UseStaticFiles
및 UseFileServer
의 추가 인스턴스를 제공할 수 있습니다. 자세한 내용은 해당 GitHub 이슈를 참조하세요.
정적 파일의 보안 고려 사항
Warning
UseDirectoryBrowser
및 UseStaticFiles
는 비밀 정보를 누출 할 수 있습니다. 프로덕션 환경에서는 디렉터리 검색을 비활성화하는 것이 좋습니다. UseStaticFiles
또는 UseDirectoryBrowser
를 통해 어떤 디렉터리가 활성화되었는지 주의 깊게 검토하세요. 전체 디렉터리와 해당 하위 디렉터리는 공개적으로 액세스할 수 있습니다. <content_root>/wwwroot
와 같은 전용 디렉터리에 공개적으로 제공하는 데 적합한 파일을 저장합니다. MVC 뷰, Razor Pages, 구성 파일 등과 해당 파일을 분리합니다.
UseDirectoryBrowser
및UseStaticFiles
로 노출된 콘텐츠에 대한 URL은 대/소문자 구분 및 기본 파일 시스템의 문자 제한이 적용됩니다. 예를 들어 Windows는 대/소문자를 구분하지 않지만 macOS 및 Linux는 대/소문자를 구분합니다.IIS에서 호스팅되는 ASP.NET Core 앱은 ASP.NET Core 모듈을 사용하여 정적 파일 요청을 비롯한 모든 요청을 앱에 전달합니다. IIS 정적 파일 처리기는 사용되지 않으며 요청을 처리할 수 없습니다.
서버 또는 웹 사이트 수준에서 IIS 정적 파일 처리기를 제거하려면 IIS 관리자에서 다음 단계를 완료합니다.
- 모듈 기능으로 이동합니다.
- 목록에서 StaticFileModule을 선택합니다.
- 동작 사이드바에서 제거를 클릭합니다.
Warning
IIS 정적 파일 처리기를 사용하도록 설정되었으며 그리고 ASP.NET Core 모듈이 올바르게 구성되지 않은 경우, 정적 파일이 제공됩니다. 이는 예를 들어 web.config 파일이 배포되지 않는 경우에 발생합니다.
- 앱 프로젝트의 웹 루트 외부에 포함
.cs
및.cshtml
외부에 코드 파일을 배치합니다. 따라서 논리적 분리가 앱의 클라이언트 쪽 콘텐츠 및 서버 기반 코드 사이에 만들어집니다. 그러면 서버 쪽 코드가 유출되지 않습니다.
추가 리소스
ASP.NET Core