The Express documentation states the following about next('route') callback:
You can provide multiple callbacks, and all are treated equally, and behave just like middleware, except that these callbacks may invoke next('route') to bypass the remaining route callback(s). You can use this mechanism to perform pre-conditions on a route then pass control to subsequent routes when there is no reason to proceed with the route matched.
and
To skip the rest of the middleware functions from a router middleware stack, call next('route') to pass control to the next route. NOTE: next('route') will work only in middleware functions that were loaded by using the app.METHOD() or router.METHOD() functions.
What is the response to the client when a middleware calls next('route') and there is no other matching route?
The response to the client is a status 404 error. This is not caught by the routers error handlers.
If you want to catch the 404 error for some reason, see this question.
However beware of matching routes:
router.get('/profile', auth.hasRole('User'), controller.showProfile);
router.get('/:id', controller.show);
I had the hasRole('User') function call next('route') if the client did not have that role. Controll was then passed to the '/:id' route as this matched the request uri, causing errors.
It will exit the Router and continue on with the rest of your application middleware and if still nothing ends in a response then a 404 error will be thrown and will be handled by the error handlers.
Related
We have a .net 7 web api, and are using FluentValidation to validate the incoming requests. Apparently FluentValidation hooks itself into the pipeline as middleware, not sure how since that is happening behind the scenes. We have middleware code that does some custom validation on a route to ensure the route itself is valid. That code works correctly, but it seems that FluentValidation is hooked in before our middleware, even if we insert the middleware immediately after app.UseAuthorization(); in program.cs.
The end result is: If the request is to an invalid route, and has validation errors that would be legit if the request itself was legit, then the response shows the validation errors instead of the invalid route message.
The preferred response message would be about the invalid route, not the validation errors.
Is there a way to get our middleware to run before FluentValidation?
Thanks for any pointers!
I set up a Cloudflare worker to redirect to our API gateway since we don't have control of the DNS and can't just set up a CNAME. The redirect works and it passes along the body and all the headers except Authorization. It receives it, and when I look at the worker console it lists it as redacted. It also redacts the user_key param I'm passing but it passes that through.
const base = 'https://myurl.com'
const statusCode = 308;
addEventListener("fetch", event => {
event.respondWith(handleRequest(event.request))
})
async function handleRequest(request) {
const url = new URL(request.url);
const { pathname, search } = url;
const destinationURL = base + pathname + search;
return Response.redirect(destinationURL, statusCode);
}
First, note that the redactions you are seeing are purely for display in the workers console. This is a feature to protect sensitive secrets from being logged, but it doesn't affect the content of any live request.
Now, with regard to what your Worker is actually doing:
This worker returns a 308 redirect response back to the client. It is then up to the client to follow the redirect, sending the same request to the new URL.
It is the client, then, that decides whether to send the Authorization header to the new location -- the behavior is NOT controlled by Cloudflare Workers. As it turns out, many clients intentionally drop the Authorization header when following redirects to a different domain name. For example, the Go HTTP client library does this, and node-fetch recently started doing this as well. (I happen to disagree with this change, for reasons I explained in a comment.)
If the client is a web browser, then the behavior is complicated. If the Authorization header was added to the request as part of HTTP basic auth (i.e. the user was prompted by the browser for a username and password), then the header will be removed when following the redirect. However, if the Authorization header was provided by client-side JavaScript code when it called fetch(), then the header will be kept through the redirect.
Probably the best way to solve this is: Don't use a 3xx redirect. Instead, have the Worker directly forward the request to the new URL. That is, instead of this:
return Response.redirect(destinationURL, statusCode);
Try this:
return fetch(destinationURL, request);
With this code, the client will not receive a redirect. Instead, the Worker will directly forward the request to the new URL, and then forward the response back to the client. The Worker acts as a middleman proxy in this case. From the client's point of view, no forwarding took place, the original URL simply handled the request.
I have been trying to intercept a server request using Cypress' intercept method.
I have noticed that Cypress can intercept requests made through the front-end/browser, however, the intercept method doesn't work if I make a request directly to the back-end server.
Let me clarify what I mean:
One thing is intercepting a request that the front-end/browser makes to the back-end server.
Another thing is intercepting a call that doesn't use the browser but calls directly the back-end endpoint.
For example:
I can create a user using the front-end interface
or I can create a user calling the back-end endpoint directly (directly calling the server).
Coming back to my question. Is there a way to intercept a call that was made directly to the back-end endpoint?
This is what I have tried so far:
I wrote a regex to intercept api/v0/customers
I then made a request to http://locahost:5440/api/v0/customers (which is the URL of the server)
Finally, I waited for the request to happen
Timeout request using Cypress intercept method
cy.intercept(/^\/api\/v0\/customers\/$/).as('createCustomer');
cy.request(createCustomer(customerData, headers));
cy.wait('#createCustomer').then(({ status, body }) => {
const customerId = body.customer_id;
console.log(body);
expect(status).equal(201);
});
Here's the problem: There was a timeout error.
As you can see in the image, I'm making a request to http://locahost:5440 which is the server URL. NOTE: I made sure the server was up and running.
The regex is also correct and it will match the endpoint http://locahost:5440/api/v0/customers
I suspect that intercept only works for requests being made through the browser. Is this assertion correct? I couldn't find this answer anywhere in the Cypress docs.
Is there a way for me to intercept a call being made directly to a server (not using the browser)?
You don't have to intercept the requests you explicitly make with cypress, just use .then to get the response, like this:
cy.request(createCustomer(customerData, headers)).then((response) => {
const customerId = response.body.customer_id;
console.log(response.body);
expect(response.status).equal(201);
});
Reference: https://docs.cypress.io/api/commands/request#Yields
Express documentation at https://expressjs.com/en/starter/faq.html shows how to handle 404 by adding the following after all middleware:
app.use(function (req, res, next) {
res.status(404).send("Sorry can't find that!")
})
But even without adding this, unhandled routes are automatically responding 404. Is there some reason why I need to explicitly handle 404s if I don't need any extra functionality there?
Express has a default 404 handler built-in so if you're perfectly fine with what it provides, then it is not necessary to provide your own 404 handler. You provide your own 404 handler when you want to control what response is sent for a 404 condition.
I went to look for the default 404 handler in the Express source code and it's a bit hard to find. It is buried in a dependent module called finalHandler which I was only able to find by stepping through the Express code which eventually stepped into this other module and you can see this module in the Express package.json as a dependency.
Here's a link to the relevant function in the finalHandler source.
Basically, if Express handlers/middleware keep calling next() and run out of more matching request handlers, they get to this final function which, if there is no pending error, then it sends a vanilla 404 response.
The relevant lines of code are these:
status = 404
msg = 'Cannot ' + req.method + ' ' + encodeUrl(getResourceName(req))
// ...
send(req, res, status, headers, msg)
I'm using self hosted ServiceStack to provide an API to integrate with a ticketing system, and have defined the following routes:
Routes
.Add<TicketsWithStatus>("tickets/{Status}")
.Add<TicketStatusCounts>("tickets");
I'm having URL encoding problems with the first route when the status contains a space. If I browse to http://myservicebase/json/syncreply/TicketsWithStatus?Status=On%20Hold I get the response I'm expecting. However, if I use the RESTful route http://mysevicebase/tickets/On%20Hold I don't get any results.
Debugging my application, I can see that the On%20Hold is being URL decoded to On Hold in the case of the json/syncreply call, but is not decoded when using the RESTful route.
How can I ensure that the status property is properly decoded when calling my service via the RESTful route?
ServiceStack doesn't UrlDecode the PathInfo, it uses the same HttpRequest.PathInfo that the ASP.NET Request object returns. You might have better success if you change it to On+Hold.