同名のフィールドを複数含むリクエストをjQuery.ajaxで投げれなかった話と泥臭い解決法

Google Closure CompilerのREST APIを呼ぶコードをPythonからJSに書き直した時にハマったので備忘録

## 元コード（Python）

元々動いていたソースでは、こんな感じでリクエスト作って投げていた。
jsCodeには、すでにコンパイル対象のJavascript文字列が入っているものとする。

```python
params = urllib.urlencode([
        ('js_code',jsCode),
        ('compilation_level', 'SIMPLE_OPTIMIZATIONS'),
        ('output_format', 'json'),
        ('output_info', 'compiled_code'),
        ('output_info', 'warnings'),
        ('output_info', 'errors'),
        ])

headers = { "Content-type": "application/x-www-form-urlencoded" }
conn = httplib.HTTPConnection('closure-compiler.appspot.com')
conn.request('POST', '/compile', params, headers)
response = conn.getresponse()
data = response.read()
conn.close()
```

ここで、"output_info"パラメータが３つあるが、リクエストではこんな感じになる。

![Developer_Tools_-_file____Users_Takuro_git_kiiServerTool_index_html.png](https://qiita-image-store.s3.amazonaws.com/0/52410/6b51ea17-8ce5-ea07-340b-5e2532b7afb5.png)


## 移植先コード - ダメな例（JavaScript）

JSにさっくりと書き直したもの。ブラウザで走らせるのでjQueryを使っている。
(node.jsのhttpで書いてもほぼ同じことになると思うが。)

```javascript
var params = {
    "js_code" : jsCode,
    "compilation_level": "SIMPLE_OPTIMIZATIONS",
    "output_format": "json",
    "output_info": ["compiled_code", "warnings", "errors"]
};
$.ajax({
    url : "http://closure-compiler.appspot.com/compile",
    type : "POST",
    contentType : "application/x-www-form-urlencoded",
    data : params,
    dataType : "json"
}).done(function(res){...}).fail(function(e){...});
```

これは、こんな感じでoutput_infoが配列になる。selectとかでよくあるパターンだけど、Closure Compiler様はデリケートなので、これはエラーになる。
具体的には"ServerError"が返ってきて、「"output_info[]"なんてパラメータは知らん。出直せ」と言われる。

![Developer_Tools_-_file____Users_Takuro_git_kiiServerTool_index_html.png](https://qiita-image-store.s3.amazonaws.com/0/52410/7a69fe97-0d5a-fa91-a63a-4d9267a2a673.png)

## 移植先コード - 泥臭く直した例（JavaScript）

公式ドキュメント見たりいろいろ探したけどクリティカルな解決策が見つからなかったので、とりあえず基本に立ち返って、自分でシリアライズする。

```javascript
var params = [
    { key : "js_code",           val : jsCode },
    { key : "compilation_level", val : "SIMPLE_OPTIMIZATIONS" },
    { key : "output_format",     val : "json" },
    { key : "output_info",       val : "compiled_code" },
    { key : "output_info",       val : "warnings" },
    { key : "output_info",       val : "errors" }
];
paramStr = $.map(params, function(n){
    return encodeURIComponent(n.key) + "=" + encodeURIComponent( n.val )
}).join("&").replace(/%20/g, "+");

$.ajax({
    url : "http://closure-compiler.appspot.com/compile",
    type : "POST",
    contentType : "application/x-www-form-urlencoded",
    data : paramStr,
    processData : false,
    dataType : "json"
}).done(function(res){...}).fail(function(e){...});
```

泥臭いけど、これは動く。

![Developer_Tools_-_file____Users_Takuro_git_kiiServerTool_index_html.png](https://qiita-image-store.s3.amazonaws.com/0/52410/6b51ea17-8ce5-ea07-340b-5e2532b7afb5.png)

とりあえずめでたし。
でも、すっきりしないー。

## (2/20追記) 正解

smzkさんから情報いただきました。1.4から追加になった traditional オプションを有効にすると、シリアライズ時の深い整形処理をやらずに、古い形式で出してくれるようだ。

```js
var params = [
    { key : "js_code",           val : jsCode },
    { key : "compilation_level", val : "SIMPLE_OPTIMIZATIONS" },
    { key : "output_format",     val : "json" },
    { key : "output_info",       val : "compiled_code" },
    { key : "output_info",       val : "warnings" },
    { key : "output_info",       val : "errors" }
];
paramStr = $.param(params, true);//traditionalオプション付きでシリアライズ

```

長いので該当箇所だけ。

いや、すっきりしました。