<p dir="auto">Not sure if this is a bug report or a feature request, since I'm not sure what you guys had in mind for this method in the first place. However, the <a href="https://angular.io/docs/ts/latest/api/http/index/RequestOptions-class.html#!#merge-anchor" rel="nofollow">documentation</a> states that it creates a copy of RequestOptions instance, and does not change the values of the instance on which it is called.</p>
<p dir="auto"><strong>Current behavior</strong><br>
As per <a href="https://github.com/angular/angular/blob/2.1.0-beta.0/modules/%40angular/http/src/base_request_options.ts#L91-L133">source</a>, the method returns <code class="notranslate">headers</code> from one or the other object (<code class="notranslate">this</code> or <code class="notranslate">options</code>). That means that <code class="notranslate">copy</code> will have access to the same list as <code class="notranslate">this</code> or <code class="notranslate">options</code>. So, if the <code class="notranslate">append</code> method is called on <code class="notranslate">copy.headers</code>, the original instance it was copied from will also have the new version of headers, since they are using the same list.</p>
<p dir="auto"><strong>Expected behavior</strong><br>
<code class="notranslate">copy.headers</code> is returned as a deep copy, so appending to <code class="notranslate">copy.headers</code> doesn't affect <code class="notranslate">this.headers</code> or <code class="notranslate">options.headers</code>. So, instead of returning <code class="notranslate">this.headers</code>, merge should return <code class="notranslate">new Headers(this.headers)</code> (same goes for <code class="notranslate">options</code>, if present).</p>
<p dir="auto"><strong>Reproduction of the problem</strong><br>
EDIT: <a href="http://plnkr.co/edit/amSzQ5B8nACveEA1Q9Rm?p=preview" rel="nofollow">plunker here</a><br>
Let's say we have custom BaseRequestOptions object globally available, that appends a custom <code class="notranslate">base-custom</code>header, and are provided through DI as Request options. Let's say we also have a CustomHttp service, that needs to append another custom header when its methods are called.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="export class CustomHttp extends Http {

    constructor(protected _backend: XHRBackend,
        protected _defaultOptions: RequestOptions,
        private _customService: CustomService) {

        super(_backend, _defaultOptions);
    }
    get(url: string, options?: RequestOptionsArgs): Observable&lt;Response&gt; {
        return customLogicBeforeReq.call(this, super.get, url, options);
    }
    // code...
}

function customLogicBeforeReq(func, url, options?){
    let reqOpts = this._defaultOptions.merge(options);
    reqOpts.headers.append(&quot;x-custom&quot;, &quot;from custom service&quot;);
    // code...
    return func.call(this, url, reqOpts);
}"><pre class="notranslate"><code class="notranslate">export class CustomHttp extends Http {

    constructor(protected _backend: XHRBackend,
        protected _defaultOptions: RequestOptions,
        private _customService: CustomService) {

        super(_backend, _defaultOptions);
    }
    get(url: string, options?: RequestOptionsArgs): Observable&lt;Response&gt; {
        return customLogicBeforeReq.call(this, super.get, url, options);
    }
    // code...
}

function customLogicBeforeReq(func, url, options?){
    let reqOpts = this._defaultOptions.merge(options);
    reqOpts.headers.append("x-custom", "from custom service");
    // code...
    return func.call(this, url, reqOpts);
}
</code></pre></div>
<p dir="auto">After appending to <code class="notranslate">reqOpts</code>, <code class="notranslate">this._defaultOptions</code> will also have that header appended (or <code class="notranslate">options</code>, if available). That means that for each request made with this service (without providing the <code class="notranslate">options</code> object), a new <code class="notranslate">x-custom</code> header will be appended. So, after 5 requests, <code class="notranslate">this._defaultOptions</code> will have an <code class="notranslate">x-custom</code> entry which is an array of 5 "from custom service" values. The expected behaviour would be that it only has one <code class="notranslate">base-custom</code> header, and none of <code class="notranslate">x-custom</code>.</p>
<ul dir="auto">
<li><strong>Angular version:</strong> 2.0.0</li>
</ul>
<p dir="auto">When headers or search is present on both the base options and the to be merged options, the to be merged options overwrite, rather than combine with the base options.</p>
<p dir="auto">This makes things like setting a default Content-Type while providing headers for other purposes impossible.</p>
<p dir="auto"><a href="https://github.com/angular/angular/blob/master/modules/angular2/src/http/base_request_options.ts#L94-L97">https://github.com/angular/angular/blob/master/modules/angular2/src/http/base_request_options.ts#L94-L97</a></p>
<p dir="auto">Headers should be able to merge with each other, overwriting on a per header basis.</p>
<p dir="auto">The same problem applies to search params. I suppose it could apply to other things, but method, body and url are all strings at this time.</p>