Controller action works but still gives 404
You're definitely on the right track, just missing out on a couple of key details!

The actionUrl function generates a normal, full URL... it's not (by default) an AJAX call. So your browser is actually navigating away from the previous page, and pinging your controller as a completely separate HTTP request.

Which leads to the next detail... Unless you're pinging your controller via AJAX, you need to then have your controller tell the request where to go. Don't forget, the request will continue on, even after your controller has worked its magic.


  ... if the controller doesn’t call a response function, Craft will continue on with its request routing...


So you'll usually want to make sure your controller ends with a directive on what to do next. The most common options are:


Render a template
Redirect to a new page
Return a JSON response (if you called it via AJAX)


The list of options to render/redirect/return are mixed in with the other BaseController Methods in the documentation...