Serving static files
Web application needs to serve static files that seldom change during request response cycle such as JavaScript codes, cascading stylesheet files and also fonts and images.
Serve static files with reverse proxy server
If your application is running behind reverse proxy server, easiest way to serve static files is to let reverse proxy server does it for you. Thus your application can focus on problem it supposes to solve.
For example if you use Nginx, you can use try_files
which will try to serve files if it exists. If it does not then let your application handles it.
server {
...
location / {
try_files $uri @myapp;
}
location @myapp {
fcgi_pass 127.0.0.1:9000
include fcgi_params;
}
}
If your application is deployed using Fano CLI, it adds web server configuration which tells web server to serves static files on behalf of application.
Serve static files within application
There are times when you need to serve files on your own, for example, you need to check if user is authorized to download file.
To serve static file in controller, you can return instance of TFileResponse
as shown in following example.
function TMyController.handleRequest(
const request : IRequest;
const response : IResponse;
const args : IRouteArgsReader
) : IResponse;
var filename : string;
begin
filename := fBaseDirectory + request.uri().getPath();
if fileExists(filename) then
begin
//serve file
result := TFileResponse.create(
response.headers(),
//ext .pdf returns content type application/pdf
//ext .png returns content type image/png
//and so on
getContentTypeFromFilename(filename),
filename
);
end else
begin
raise ENotFound.create(filename + ' not found');
end;
end;
TStaticFilesMiddleware
is middleware implementation which can serve static files if they exists. You can attach it application middleware list so that it applies to all routes.
var mimeTypes : IKeyValuePair;
...
mimeTypes := TKeyValuePair.create();
//register all file types you need to handle
mimeTypes.setValue('pdf', 'application/pdf');
mimeTypes.setValue('jpg', 'image/jpg');
mimeTypes.setValue('png', 'image/png');
appMiddlewares.add(
TStaticFilesMiddlewares.create(
'/path/to/static/files/base/directory',
mimeTypes
)
);
or registering it in dependency container using its factory class TStaticFilesMiddlewareFactory
,
container.add(
'staticFiles',
TStaticFilesMiddlewareFactory.create()
.baseDirectory('/path/to/static/files/base/directory')
.addMimeType('pdf', 'application/pdf')
.addMimeType('jpg', 'image/jpg')
.addMimeType('png', 'image/png')
);
...
appMiddlewares.add(container['staticFiles'] as IMiddleware);
TStaticFilesMiddleware
decides to serve file based on existence of file. If you need more elaborate checks, you can inherit this middleware and override its handleRequest()
method.
You can use several middlewares in case of multiple base directories. For example you serve PDF files from different path than image files.
container.add(
'imageStaticFilesMw',
TStaticFilesMiddlewareFactory.create()
.baseDirectory('/path/to/image/files/base/directory')
.addMimeType('jpg', 'image/jpg')
.addMimeType('png', 'image/png')
);
container.add(
'pdfStaticFilesMw',
TStaticFilesMiddlewareFactory.create()
.baseDirectory('/path/to/pdf/files/base/directory')
.addMimeType('pdf', 'application/pdf')
);
...
appMiddlewares
.add(container['imagesStaticFilesMw'] as IMiddleware);
.add(container['pdfStaticFilesMw'] as IMiddleware);