/**
* Generate proxy
* #param list
*/
export function createProxy(list: ProxyList = []) {
const ret: ProxyTargetList = {};
for (const [prefix, target] of list) {
const isHttps = httpsRE.test(target);
// https://github.com/http-party/node-http-proxy#options
ret[prefix] = {
target: target,
changeOrigin: true,
ws: true,
rewrite: (path) => path.replace(new RegExp(`^${prefix}`), ''),
// https is require secure=false
...(isHttps ? { secure: false } : {}),
};
}
console.log('proxy list');
console.log(ret);
return ret;
}
I have above method to create a list of proxy based on different prefix which defined in .env.development.
VITE_PROXY = [["/basic-api","http://127.0.0.1:3100"],["/api","http://127.0.0.1:8080"],["/upload","http://localhost:3300/upload"]]
But when I request url http://127.0.0.1/api/xxx, it is not rewrite to http://127.0.0.1:8080 as expected.
then I just add return path in rewrite function like this:
rewrite: (path) =>
{path.replace(new RegExp(`^${prefix}`), '');return path},
Then it works.
I am confused now. What's the difference there? I googled a lot about vite proxy rewrite, normally, no need to add return statement like I just did.
Thanks!
Hint: rewrite: (path) => {path.replace(new RegExp(^${prefix}), '');return path},
will return you the original, untransformed path, since replace returns a new string. Please see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace.
So probably the regex or underlying logic is not correct.
Related
I'm writing CY test and was trying to solve it by myself for couple of hours but unsuccessfully. Could you please help me here a bit :)
Each time I run the test I'm getting new URL, e.g.
https://website.com/en/info/is/here/
And I need to save only
/en/info/is/here/ (so without domain name)
I need to compare it later with another href.
Could you please advise me the way how to do it or at least the direction? Thanks a lot!
The cy.location() command gives you named parts, so from the example pathname is the part you need
cy.visit('http://localhost:8000/app/index.html?q=dan#/users/123/edit')
cy.location().should((loc) => {
..
cy.wrap(loc.pathname).as('url1')
...
})
If you have search or hash as well
cy.visit('http://localhost:8000/app/index.html?q=dan#/users/123/edit')
cy.location().should((loc) => {
..
cy.wrap(loc.pathname + loc.search + loc.hash).as('url1')
...
})
You can use .split() on the URL string.
Where you save it depends on the location of it's use.
Inside one test:
let pathname
cy.url().then((url) => url.split('/').slice(3)).as('pathname1')
...
cy.get('#pathname1').then(pathname1 => {
expect(pathname1).to.eq(pathname2)
})
Between tests:
let pathname1
it('gets first pathname', () => {
cy.url().then((url) => pathname1 = url.split('/').slice(3))
})
it('uses first pathname', () => {
expect(pathname1).to.eq(pathname2)
})
Use the URL interface to parse your string (also used by cy.location)
const urlString = 'https://website.com/en/info/is/here/'
const url = new URL(urlString)
const pathname = url.pathname // yields "/en/info/is/here/"
You can use the following :
let firstUrl = null;
let secondUrl = null;
cy.url().then(url => {
firstUrl = url;
});
/* sometimes later */
cy.url().then(url => {
secondUrl = url;
});
/* sometimes later */
expect(firstUrl).to.equal(secondUrl)
If you want to just compare some part of these URL I recommend you using a regex expressions.
You can use the javascript split to do this:
let partUrl
cy.url().then((url) => {
partUrl = url.split('com')[1] //saves /en/info/is/here/
})
You could use .replace() and the Cypress baseUrl value, and then store that value in a Cypress environment variable.
cy.url().then((url) => {
Cypress.env('someUrl', url.replace(Cypress.config('baseUrl'), '');
}).then(() => {
cy.log(Cypress.env('someUrl'));
})
My API clients will pass the session token in the header or query string like:
Http Header with key/value like MyApp-Token abc123
Url:
https://api.example.com/v1/board?authToken=abc123
val secureRoutes =
authenticateToken() { authenticatedContext =>
path("board") {
get {
complete(s"board#index route ${authenticatedContext.user.username}")
}
}
}
Is there a built-in directive that can do this for me or do I have to somehow create my own custom directive that will first look in the HTTP headers, and if not there then look to see if there is a query string value at the key authToken ?
If I have to create a custom directive, any examples I can follow or learn from?
I know I can get a HTTP header using the built-in directive:
headerValueByName("x-authToken") { authToken =>
get {
complete(s"board#index route 2.1 $authToken")
}
}
And there is also a directive to get the value from a query string:
parameter("authToken") { authToken =>
...
}
How could I combine both of them, and then internally I would want to make a database call, and then instead of returning authToken I want to return a custom case class that will contain data I just loaded from the database like:
case class AuthenticatedContext(authToken: String, user: User, ...)
We can always construct a custom directive or compose the directives as shown below:
case class AuthenticatedContext(authToken: String)
def validateTokenAndGetAuthContext(token: String): Future[AuthenticatedContext] = {
Future.successful(AuthenticatedContext(token))
}
val authToken: Directive1[AuthenticatedContext] = optionalHeaderValueByName("authToken").flatMap {
case Some(token) =>
onComplete(validateTokenAndGetAuthContext(token)).flatMap {
case Failure(_) => reject(AuthorizationFailedRejection)
case Success(value) => provide(value)
}
case None =>
parameter("authToken".optional).flatMap {
case Some(token) =>
onComplete(validateTokenAndGetAuthContext(token)).flatMap {
case Failure(_) => reject(AuthorizationFailedRejection)
case Success(value) => provide(value)
}
case None => reject(AuthorizationFailedRejection)
}
}
It's constructed using HeaderDirectives, ParameterDirectives and FuturesDirectives.
I have a custom veevalidate rule that I use to see if the value entered is already in an array in that component. I want to use this rule in different components with different arrays. Is there a way to do this? Here is my current rule in just one component
const isUnique = (value) => {
const reg = new RegExp(`^${value}$`, 'i');
const inputValue = this.myArray.filter(str => reg.test(str));
if (inputValue.length > 0) {
return {
valid: false,
data: {
message: `The ${inputValue} already exists.`,
},
};
}
return { valid: true };
};
Validator.extend('unique', {
validate: isUnique,
getMessage: (field, params, data) => data.message,
});
You sure can - either you can use the existing rule called oneOf which is documented here, or you can change your rule to accept parameters. It looks like your rule is case-insensitive, so probably you'd want to stick with that. All you would need to do is accept a 2nd parameter to your isUnique function and then use that instead of this.myArray:
const isUnique = (value, values) => {
const reg = new RegExp(`^${value}$`, 'i');
const inputValue = values.filter(str => reg.test(str));
Then in your template, you would call it like this:
<ValidationProvider :rules="{isUnique:myArray}">
I'm using this Angular service to get data from Express:
getRestaurants(districtId) : Observable<void[]>{
let params: URLSearchParams = new URLSearchParams();
params.set('id', districtId);
return this.http.get(this.url, { search: params })
.map((res:Response) => res.json())
.catch((error:any) => Observable.throw(error.json().error || 'Server error'));
}
I was using this URL http://localhost:5050/api/district/restaurants?id=8
It works fine if in Express I use req.query But I need to use this new URL http://localhost:5050/api/district/:id/restaurants and use req.params in Express.
My problem is that I can't set the :id parameter using Angular without modifying the URL string and I suppose that there is a better way to do this task. Thanks for your help
What about this:
private url = 'http://localhost:5050/api/district/:id/restaurants';
private _prepareUrl(districtId: number): string {
return this.url.replace(':id', districtId);
}
getRestaurants(districtId) {
// ...
this.http.get(this._prepareUrl(districtId), ...);
// ...
}
You could use the Router's function createUrlTree, but you will have a prepare-function too..
private urlPrefix = 'http://localhost:5050/api';
constructor(private _router: Router) { }
private _prepareUrl(districtId: number): string {
return this.urlPrefix + this._router.createUrlTree(['district', districtId, 'restaurants']).toString();
}
getRestaurants(districtId) {
// ...
this.http.get(this._prepareUrl(districtId), ...);
// ...
}
EDIT: I found the problem -- my style sheet was relatively linked when it should have been an absolute link.
The express get handler in question is intended to be called when someone clicks a generated link -- it works fine, but then I tried to add a second request parameter and now the rendered page doesn't seem to have any CSS styling and is just keeps loading.
First, I use just the :creator request parameter. Here's the code:
//djApp.get('/:creator/:hash', function (req, res) {
djApp.get('/:creator/', function (req, res) {
var path = req.params.creator.toLowerCase();
for(booth in boothList) {
if (path == boothList[booth].creator.toLowerCase()) {
res.sendFile(__dirname+'/public/index.html', setTimeout(function () {
for (c in clients) {
if (clients[c].url && clients[c].url == path) {
clients[c].socket.emit('redirectUser', {'booth': boothList[booth]});
}
}
}, 500));
/*var hash = req.params.hash;
if (hashes.indexOf(hash) > -1) {
console.log("path is "+path+"\nhash is "+hash+"\nhashIndex is "+hashes.indexOf(hash));
hashes.splice(hashes.indexOf(hash), 1);
res.sendFile(__dirname+'/public/index.html', setTimeout(function () {
for (c in clients) {
if (clients[c].url && clients[c].url == path) {
clients[c].socket.emit('redirectUser', {'booth': boothList[booth]});
}
}
}, 500));
}*/
}
}
});
});
djApp.use('/', express.static(__dirname+'/public'));
This is the generated URL that the handler is using:
http://localhost:3001/Aweeeezy
Here is a screenshot demonstrating that the HTML is sent and properly links the CSS and JS as expected:
Next I comment out the app.get line with the single request parameter and the logic block that sends the html file and then uncomment the app.get line with two request parameters and an identical logic block for sending the html file, only it sits inside a if condition related to the additional request parameter. Here's the code:
//djApp.get('/:creator/', function (req, res) {
djApp.get('/:creator/:hash', function (req, res) {
var path = req.params.creator.toLowerCase();
for(booth in boothList) {
if (path == boothList[booth].creator.toLowerCase()) {
var hash = req.params.hash;
if (hashes.indexOf(hash) > -1) {
console.log("path is "+path+"\nhash is "+hash+"\nhashIndex is "+hashes.indexOf(hash));
hashes.splice(hashes.indexOf(hash), 1);
res.sendFile(__dirname+'/public/index.html', setTimeout(function () {
for (c in clients) {
if (clients[c].url && clients[c].url == path) {
clients[c].socket.emit('redirectUser', {'booth': boothList[booth]});
}
}
}, 500));
/*res.sendFile(__dirname+'/public/index.html', setTimeout(function () {
for (c in clients) {
if (clients[c].url && clients[c].url == path) {
clients[c].socket.emit('redirectUser', {'booth': boothList[booth]});
}
}
}, 500));*/
}
}
}
});
});
djApp.use('/', express.static(__dirname+'/public'));
This is the generated URL that the handler is using:
http://localhost:3001/Aweeeezy/a35969699812c71ef8fde58cafebe644dd18ed7b
Output is:
path is aweeeezy
hash is a35969699812c71ef8fde58cafebe644dd18ed7b
hashIndex is 0
So you can see that everything works as expected inside the handler -- at least up to the code that is identical to the working case, but my browser now renders the page like this:
What it really comes down to is the difference from /:creator to /:creator/:hash in the request handler URL -- but every example I see for use of multiple parameters does what I'm trying to do.
What's going on?!
Change the link to the style sheet to be an absolute link.