get_permalink
will fetch the URL of the current post within a loop. If you call it on an archive page, then what WP thinks is the “current post” is actually the first post that you are about to loop through and so you end up with that post’s permalink rather than the current page’s URL.
I’ve not found a better way than this, which effectively rebuilds the URL from the current request:
global $wp;
$current_url = home_url( add_query_arg( array(), $wp->request ) );
Doing it this way rather than messing with $_SERVER
, which I’ve seen in various online posts, at least ensures that you easily get your canonical hostname & your protocol right.