Comments (11)
We ended up using a slight modification that preserves original grouping of multiValues and has some documentation:
/**
* Patches lack of
* https://developer.mozilla.org/en-US/docs/Web/API/Location/search in event.
* Inspired by
* https://github.com/aws-samples/amazon-cloudfront-functions/issues/11.
* @param obj The weird format exposed by CloudFront
* https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/functions-event-structure.html#functions-event-structure-query-header-cookie
* @returns {string} Tries to return the same as
* https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/toString
*/
function getURLSearchParamsString(obj) {
var str = [];
for (var param in obj) {
if (obj[param].multiValue) {
str.push(
obj[param].multiValue.map((item) => param + "=" + item.value).join("&")
);
} else if (obj[param].value === "") {
str.push(param);
} else {
str.push(param + "=" + obj[param].value);
}
}
return str.join("&");
}
Now
?aa=11&bb=22&aa=33&bb=44,55&cc=66&dd&ee
results in
?aa=11&aa=33&bb=22&bb=44,55&cc=66&dd&ee
instead of
?aa=11,33&bb=22,44,55&cc=66&dd&ee
from amazon-cloudfront-functions.
@joknoxy do we need to handle the case where the query string has multi values?
I have modified objectToQueryString
as shown below.
function objectToQueryString(obj) {
var str = [];
for (var param in obj)
if (obj[param].multiValue)
str.push(encodeURIComponent(param) + "=" + encodeURIComponent(obj[param].multiValue.map((item) => item.value).join(',')))
else if (obj[param].value == '')
str.push(encodeURIComponent(param));
else
str.push(encodeURIComponent(param) + "=" + encodeURIComponent(obj[param].value));
return str.join("&");
}
While checking further, I noticed an issue with this approach. If the query string is already an encoded string, we will be encoding it again in the cloudfront function. So I end up using this:
function objectToQueryString(obj) {
var str = [];
for (var param in obj)
if (obj[param].multiValue)
str.push(param + "=" + obj[param].multiValue.map((item) => item.value).join(','));
else if (obj[param].value == '')
str.push(param);
else
str.push(param + "=" + obj[param].value);
return str.join("&");
}
from amazon-cloudfront-functions.
Adapted JSDoc types from https://www.npmjs.com/package/@types/aws-lambda
/**
* Patches lack of
* https://developer.mozilla.org/en-US/docs/Web/API/Location/search in event.
* Inspired by
* https://github.com/aws-samples/amazon-cloudfront-functions/issues/11.
* @param {import("aws-lambda"). CloudFrontFunctionsQuerystring} querystring The weird format exposed by CloudFront
* https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/functions-event-structure.html#functions-event-structure-query-header-cookie
* @returns {string} Tries to return the same as
* https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/toString
*/
function getURLSearchParamsString(querystring) {
var str = [];
for (var param in querystring) {
var query = querystring[param];
var multiValue = query.multiValue;
if (multiValue) {
str.push(multiValue.map((item) => param + '=' + item.value).join('&'));
} else if (query.value === '') {
str.push(param);
} else {
str.push(param + '=' + query.value);
}
}
return str.join('&');
}
from amazon-cloudfront-functions.
It's especially confusing that AWS offers a querystring
helper package which exposes a stringify
method that doesn't actually work with their own representation of the event.request.querystring
object https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/functions-javascript-runtime-features.html#writing-functions-javascript-features-builtin-modules-query-string
from amazon-cloudfront-functions.
@longzheng Instead of
CloudFrontFunctionsEvent
I believe it should beCloudFrontFunctionsEvent['request']['querystring']
.
Sorry I made a typo when I edited it, it can also be CloudFrontFunctionsQuerystring
since that's what CloudFrontFunctionsEvent['request']['querystring']
references. I'll update my comment.
from amazon-cloudfront-functions.
thanks @longzheng for sharing #11 (comment), got this working thanks to it 🚀
for anyone else trying to build
cloudfront function to redirect to non trailing slash url while preserving query string
refer 👇
function handler(event) {
// Get the request object from the event
var request = event.request;
// Get the URI of the requested resource
var uri = request.uri;
// Get the query string parameters
var queryStringParameters = request.querystring;
// Remove all trailing slashes from the URI using a regular expression
var newUri = uri.replace(/\/+$/, "");
// Check if the URI had trailing slashes
if (newUri !== uri) {
// Check if querystring is not empty
var hasQueryString = Object.keys(queryStringParameters).length > 0;
// Construct the new URI without the trailing slashes and include the query parameters if querystring is not empty
var redirectUri = newUri + (hasQueryString ? '?' + getURLSearchParamsString(queryStringParameters) : '');
// Redirect to the new URI without the trailing slashes
var response = {
statusCode: 301,
statusDescription: "Moved Permanently",
headers: {
location: { value: redirectUri },
},
};
return response;
}
// If there's no trailing slash, proceed with the request as is
return request;
}
// Helper function to format query string parameters
function getURLSearchParamsString(querystring) {
var str = [];
for (var param in querystring) {
var query = querystring[param];
var multiValue = query.multiValue;
if (multiValue) {
str.push(multiValue.map((item) => param + '=' + item.value).join('&'));
} else if (query.value === '') {
str.push(param);
} else {
str.push(param + '=' + query.value);
}
}
return str.join('&');
}
from amazon-cloudfront-functions.
While checking further, I noticed an issue with this approach. If the query string is already an encoded string, we will be encoding it again in the cloudfront function. So I end up using this:
Thank you @akarsh-k, this works perfectly with the CloudFront event example structure.
from amazon-cloudfront-functions.
@longzheng Instead of CloudFrontFunctionsEvent
I believe it should be CloudFrontFunctionsEvent['request']['querystring']
.
from amazon-cloudfront-functions.
okay so I updated this a bit on my end because I was worried about double encoding, but also worried about not having encodings properly in query params. I'm also not redirecting here like in the example above. this was super helpful though, thank you @joknoxy !
function isEncoded(uri) {
uri = uri || '';
return uri !== decodeURIComponent(uri);
}
function fullyDecodeURI(uri){
while (isEncoded(uri)) {
uri = decodeURIComponent(uri);
}
return uri;
}
function encode(param) {
return encodeURIComponent(fullyDecodeURI(param));
}
function objectToQueryString(obj) {
var str = [];
for (var param in obj) {
if (obj[param].multiValue) {
str.push(encode(param) + "=" + obj[param].multiValue.map((item) => encode(item.value)).join(','));
} else if (obj[param].value == '') {
str.push(encode(param));
} else {
str.push(encode(param) + "=" + encode(obj[param].value));
}
}
return str.join("&");
}
function handler(event) {
var request = event.request;
request.headers["x-forwarded-host"] = request.headers.host;
request.querystring = objectToQueryString(request.querystring);
return request;
}
from amazon-cloudfront-functions.
Thanks for the comments, it helps me to solve my issue.
Here is my code for redirect
with query params
+ adding missing /index.html
for SPA or SSG websites
https://gist.github.com/karpolan/ecce9c372bebb448ee04cc240ca5c8aa
from amazon-cloudfront-functions.
Related Issues (20)
- URL redirect/rewrite HOT 1
- Additional "s" in the folder path in the following command HOT 1
- Please provide an example with a simple cookie manipulation HOT 8
- Can AWS Parameter Store variables or secrets be used in CloudFront functions? HOT 6
- x-frame-options works but not x-xss-protection HOT 1
- How can I redirect with a huge list of urls? HOT 2
- Unable to use CloudFront Function "Test" Feature with host.value
- Use of crypto module? HOT 1
- Using cloudfron functions to remove server header HOT 3
- redirect on response HOT 3
- Unable to get clientIP HOT 1
- How to make a rewrite? HOT 1
- Verify cognito jwt with cloudfront function
- Response interceptor
- `Date` object has no `toUTCString` HOT 1
- anti-hotlinking with referer header
- url redirect adding multiple path HOT 1
- Decrypt a Cookie HOT 1
- Redirection problem with Nextjs application deployed on aws s3 and cloundfront as static application
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from amazon-cloudfront-functions.