The RayCast2D answer is probably the nicest one so far (including my own).
The problem you're having using Area2D is trying to check at the time of the attack you're producing.
The best way if you want to stick with an Area2D is to use signals, but not for a realtime check, rather to add them to an array of "hit-able" targets when they enter, and remove them when they exit.
When you attack, your attack function automatically hits all of the targets within the array (all of them the game have told you have come within the area you can hit, and haven;t left it yet).
You'd use something like the following to get the targets your attack would affect into the array. How you implement the damage is totally separate, so I'll leave that out.
# your array
var targetsInHitbox
func _on_Area2D_body_entered(body):
# add the newly entered body to the array
targetsInHitbox.append(body)
func _on_Area2D_body_exited(body):
# remove works on the number of element you give it
# so you need to use the find function inside it to get
# the right number to remove
targetsInHitbox.remove(targetsInHitbox.find(body))
Note if you've renamed your Area2D, then the "Area2D" part of the func will change to match your naming. If you connect in the editor (which you should), then the func creation and naming will be taken care of for you.
When your player attacks, you'll then want to use a for loop to iterate through the array, and perform your attack on each.
Apologies if the GDScript isn't perfect, I use NativeScript/C++ for my Godot scripting... The approach is sound though.