There are 4 distinct trigger events in CloudFront's Lambda@Edge enhancement. Their interaction with the cache is in bold, and becomes important, later:
- Viewer Request - fires on every request, before the cache is checked on request arrival; a spontaneously-generated response is not cached
- Origin Request - fires only on cache miss, before request goes to the origin; if this trigger generates a response, no HTTP request is sent to the origin, and the response will be stored in the cache, if cacheable
- Origin Response - fires only on cache miss, when response returns from origin, before response is checked for cacheability and stored in the cache; if this trigger modifies the response, the modified response is what is stored in the cache, if cacheable
- Viewer Response - fires immediately before response is returned to viewer, whether cache hit or miss; any modifications to the response made by this trigger are not cached
One Lambda function, correctly written to understand where it has been fired within the transaction cycle, can be triggered at any combination of these points -- but since these events all occur at different times, it isn't possible to handle more than a single event with one invocation of the trigger function.
However, note the points in bold, above. You can substantially reduce the number of trigger invocations in many cases by using the origin-side triggers. As noted above, using these triggers results in the response of the triggers being cacheable -- so when your redirect trigger fires, if it generates a redirect, the redirect can be cached, and the next request doesn't need to invoke the trigger at all. Similarly, adding your HSTS header to a cacheable response in an origin response trigger means that future cache hits will return the modified response with HSTS headers, without the trigger firing.