Is there a way to set the host header on a service callout?

I am trying to use a ServiceCallout policy to call an API, and I want to set my own host header. No matter what I try, the edge always overwrites my host header before sending the request so the backend never gets my custom value.

I tried to set the headers in the ServiceCallout policy:

<Request clearPayload="true">
     <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
     <Set>
         <Headers>
             <Header name="host">foobar.com</Header>
         </Headers>
     </Set>
</Request>

We are able to set this header on a target endpoint be doing an AssignMessage:

<AssignMessage async="false" continueOnError="false" enabled="true" name="HostHeader">
    <DisplayName>HostHeader</DisplayName>
    <Properties/>
    <AssignVariable>
        <Name>target.header.host</Name>
        <Value>foobar.com</Value>
    </AssignVariable>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
</AssignMessage>

But a similar method does not work for ServiceCallout:

<AssignMessage async="false" continueOnError="false" enabled="true" name="calloutRequest">
    <DisplayName> calloutRequest </DisplayName>
    <AssignTo createNew="true" type="request">calloutRequest</AssignTo>
    <Set>
        <Verb>GET</Verb>
	<Headers>
		<Header name="host">foobar.com</Header>
	</Headers>
    </Set>
</AssignMessage>


<AssignMessage async="false" continueOnError="false" enabled="true" name="HostHeader">
    <DisplayName>HostHeader</DisplayName>
    <Properties/>
    <AssignVariable>
        <Name>calloutRequest.header.host</Name>
        <Value>foobar.com</Value>
    </AssignVariable>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
</AssignMessage>


<ServiceCallout async="false" continueOnError="false" enabled="true" name="callout">
    <DisplayName>callout</DisplayName>
    <Properties/>
    <Request clearPayload="true" variable="calloutRequest"/>
    <Response>calloutResponse</Response>
    <HTTPTargetConnection>
        <Properties/>
        <URL>https://postman-echo.com/get</URL>
    </HTTPTargetConnection>
</ServiceCallout>

Is there a way to make sure my host header value makes it to the backend of a ServiceCallout?

1 7 1,203
7 REPLIES 7

The host header is set based on the url. Don't believe it can be overwritten

hi @dknezic , this should be made supported by service callout ? something similar to how it is done via "target.header.host" from target endpoint

I guess it isn’t. ??

Yes, it does not support. Have no luck trying with "servicecallout.${policy-name}.target.header.host" as well. @dchiesa1 can we raise a feature request for to support host overriding in service callout ? similar to how's target endpoint is done. 

Yes, the variable name you tried would seem to be the obvious one. I looked...., and found that it is not implemented in the current code. I filed a feature request as you suggested, the internal reference is b/239056604 . I don't have control or much influence over the priority that will be assigned to this FR.  You may be able to influence the priority by connecting through your account team and asking for this particular feature (mention the internal reference I noted above). Implementing it should be pretty simple, though, once it is picked up from the backlog.

We can try filing such a feature request, yes. But before doing so, I would like to better understand the requirement here. Is the hostname in the URL not the appropriate hostname? If not, why not? Can you elaborate a little on your scenario?

Hi Team,

We are facing same issue as above and unable to set custom value for 'host' header. We are using a Servicecallout policy to route to Target but have F5 system that looks for 'host' header for dynamic routing.

Could you please let us know if there is a fix to set 'host'  in Servicecallout policy.

We tried below options but none of them helped.

JS policy.

context.setVariable('servicecallout.ServiceCallout.{policyname}.target.header.host', customhdrHost);

AssignMessage:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage async="false" continueOnError="false" enabled="true" name="AssignMessageSetHostHeader">
<IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
<AssignTo createNew="true" transport="http" type="request">myRequest</AssignTo>
<Set>
<Headers>
<Header name="host">{customhostheader}</Header>
</Headers>
</Set>
</AssignMessage>

While doing an echo to mocktarget, we see the host header as mocktarget and not the above customhosttarget that we tried setting. 

The feature request is in the backlog. The eng team have not prioritized work on it. I think part of the reason is, no one here understands why the solution to your problem (The F5 needs to see the request with a specific hostname) is not to just do the right thing with DNS. 

I understand what you are asking for, and I don't understand why you believe you need this capability in the Apigee Gateway.  I understand it would be nice to have, I understand the utility. But there is a straightforward workaround - specifically, assign a proper hostname (DNS CNAME) to the target and address the target in the normal way. In fact most people would say, the "workaround" I described is the CORRECT way to do what you want.  If you want multiple hostnames to resolve to the same IP address, then register multiple CNAMEs. Is this not an acceptable approach? If not why not? Can you explain?