diff --git a/src/prelude/url.ts b/src/prelude/url.ts
index ce75fe89d12e90a31905f9d889e028b919007019..c7f2b7c1e745df394478689727a198a7ae093516 100644
--- a/src/prelude/url.ts
+++ b/src/prelude/url.ts
@@ -4,7 +4,7 @@ export function query(obj: {}): string {
 		.reduce((a, [k, v]) => (a[k] = v, a), {} as Record<string, any>);
 
 	return Object.entries(params)
-		.map((e) => `${e[0]}=${e[1]}`)
+		.map((e) => `${e[0]}=${encodeURIComponent(e[1])}`)
 		.join('&');
 }
 
diff --git a/test/prelude/url.ts b/test/prelude/url.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1f814968a6d9d8b6aee2b5886cb78fc913f85c40
--- /dev/null
+++ b/test/prelude/url.ts
@@ -0,0 +1,13 @@
+import * as assert from 'assert';
+import { query } from '../../src/prelude/url';
+
+describe('url', () => {
+	it('query', () => {
+		const s = query({
+			foo: 'ふぅ',
+			bar: 'b a r',
+			baz: undefined
+		});
+		assert.deepStrictEqual(s, 'foo=%E3%81%B5%E3%81%85&bar=b%20a%20r');
+	});
+});