angular.jsはdataがundefinedだった場合にContent-Type headerを消す
はじめに
requestのcontent typeをみて、responseの形式を変えたいと思うことがありました。 そのためにheadersを変えてrequestを投げてみたのですが、どうも上手くcontent typeが付かない。 なぜだろうと思って調べてみたのでした。
実験環境
とりあえず、挙動を調べるためにテキトウな実験環境を作る。
content typeを確認するためのserverの作成
とりあえず、以下のような挙動をするserverを書く。httpコマンドはhttpieをinstallしていないとないかもしれません。 requestのheaderの内容を返すserverです。めんどくさかったのでpythonで書きました。
$ python server.py & Serving on port 8000... $ http http://localhost:8000 "Content-Type:application/json" | grep CONTENT "CONTENT_LENGTH": "", "CONTENT_TYPE": "application/json", $ http http://localhost:8000 "Content-Type:text/html" | grep CONTENT "CONTENT_LENGTH": "", "CONTENT_TYPE": "text/html", $ http http://localhost:8000 | grep CONTENT "CONTENT_LENGTH": "", "CONTENT_TYPE": "text/plain",
渡したcontent typeが適切に返っていそうです。
code
# -*- coding:utf-8 -*- import logging import json logger = logging.getLogger(__name__) from wsgiref.util import setup_testing_defaults from wsgiref.simple_server import make_server def simple_app(environ, start_response): setup_testing_defaults(environ) status = '200 OK' headers = [('Content-type', 'text/json; charset=utf-8')] start_response(status, headers) data = {k: v for k, v in environ.items() if isinstance(v, (int, float, str, bool))} ret = bytes(json.dumps(data, indent=2, ensure_ascii=False), encoding="utf-8") return [ret] httpd = make_server('', 8000, simple_app) print("Serving on port 8000...") httpd.serve_forever()
angularのAPI越しにrequestを投げてみる
node.jsで動くようなclientも作成しておきます。以下の様な挙動です。
node app.js input: {} Content type: text/plain input: {"headers":{"Content-Type":"application/json"}} Content type: text/plain input: {"headers":{"Content-Type":"application/json"}, "data":""} Content type: application/json
input部分に着目して欲しいのですが、headersにcontent typeを与えても無視されています。 一方でdataオプションの値を追加するとcontent typeが認識されるようです。
code
require('../setup')(function(angular){ 'use strict'; function callAPI($http){ var data = { method: "GET", url: "http://localhost:8000", }; return function(opts){ console.log("input: %s", JSON.stringify(opts)); return $http(Object.assign({}, data, opts)) .then(function(response){ console.log("Content type: %s", response.data.CONTENT_TYPE); }).catch(function(err){ console.log("!"); console.log(err); }); }; } callAPI.$inject = ["$http"]; angular.module("app", []) .factory("callAPI", callAPI); var inj = angular.injector(["app", "ng"]); var api = inj.get("callAPI"); api({}).then(function(){ return api({headers: {"Content-Type": "application/json"}}); }).then(function(){ return api({headers: {"Content-Type": "application/json"}, data: ""}); }); });
angular.jsのコードを見てみる
必要となりそうなコードの部分だけ抜粋。たしかにdataがundefinedだった場合に、わざわざdeleteしている。
/** * @license AngularJS v1.4.8 * (c) 2010-2015 Google, Inc. http://angularjs.org * License: MIT */ // snip.. function $http(requestConfig) { // snip.. var serverRequest = function(config) { var headers = config.headers; var reqData = transformData(config.data, headersGetter(headers), undefined, config.transformRequest); // strip content-type if data is undefined if (isUndefined(reqData)) { forEach(headers, function(value, header) { if (lowercase(header) === 'content-type') { delete headers[header]; } }); }