Fun fact: for servers that are not too particular about the Content-Type they receive or the presence of extra object attributes, it is also possible to submit (fixed) well-formed JSON using HTML forms with no JavaScript and a dash of hackery.
<form method="POST" enctype="text/plain" action="http://example.com">
<input name='{"key1":"val1","params":{"input":"value","list":[],},"dummy":"' value='"}' hidden>
<button>Submit</button>
</form>
The important bit is to include a "dummy" key at the end of the JSON object, and an input value that closes the quotes and any open curl braces. That way the "=" character sent in the encoding of the form elements doesn't interfere with the meaningful JSON content.There might be a clever way to get it to submit dynamic JSON that changes based on user input without JavaScript, but I haven't thought enough about it.
This technique is sometimes useful for CSRF attacks.