{ Community }
  • Academy
  • Docs
  • Developers
  • Resources
    • Community Articles
    • Apigee on GitHub
    • Code Samples
    • Videos & eBooks
    • Accelerator Methodology
  • Support
  • Ask a Question
  • Spaces
    • Product Announcements
    • General
    • Edge/API Management
    • Developer Portal (Drupal-based)
    • Developer Portal (Integrated)
    • API Design
    • APIM on Istio
    • Extensions
    • Business of APIs
    • Academy/Certification
    • Adapter for Envoy
    • Analytics
    • Events
    • Hybrid
    • Integration (AWS, PCF, Etc.)
    • Microgateway
    • Monetization
    • Private Cloud Deployment
    • 日本語コミュニティ
    • Insights
    • IoT Apigee Link
    • BaaS/Usergrid
    • BaaS Transition/Migration
    • Apigee-127
    • New Customers
    • Topics
    • Questions
    • Articles
    • Ideas
    • Leaderboard
    • Badges
  • Log in
  • Sign up

Get answers, ideas, and support from the Apigee Community

  • Home /
  • Edge/API Management /
avatar image
8

How to handle multi-value headers in Javascript?  

  • Export to PDF
Dino   created · Mar 31, 2015 at 03:18 PM · 12k Views · Dino-at-Google edited · Feb 27, 2019 at 08:28 PM

Updated with New Information!

The Javascript callout capability in Apigee Edge is super flexible, making it nice for doing just about anything to a request or response message, whether that is parsing it, extracting data, transforming it, searching, validating, setting default values, and so on. Just running through that list makes me think I could post a series of quick articles here on the community site, outlining how to do each of these things. If I were to do that, I think @Birute Awasthi here at Apigee would be very pleased (She's the community advocate). I'll make no commitments, because I have a day job. But I will write at least ONE article in the set, on this topic: handling multi-value headers.

RFC2616, the IETF RFC that defines the HTTP protocol says:

> Multiple message-header fields with the same field-name MAY be present in a message if and only if the entire field-value for that header field is defined as a comma-separated list [i.e., #(values)]. It MUST be possible to combine the multiple header fields into one "field-name: field-value" pair, without changing the semantics of the message, by appending each subsequent field-value to the first, each separated by a comma. The order in which header fields with the same field-name are received is therefore significant to the interpretation of the combined field value, and thus a proxy MUST NOT change the order of these field values when a message is forwarded.

Clearly, it is legal for an HTTP request or response to have multiple values for a single header, or multiple instances of the same "header key". A good example might be, Cookie headers. A request may include multiple Cookie headers, something like:

 GET /alpha/beta?q=7
 Host: www.example.com
 Cookie: JSESSIONID=alphabeta120394049
 Cookie: AWSELBID=baaadbeef6767676767690220

And a response might include multiple Set-Cookies:

 HTTP/1.1 200 OK
 Server: Apigee-Edge
 Set-Cookie: JSESSIONID=alphabeta120394049; HttpOnly
 Set-Cookie: AWSELBID=baaadbeef6767676767690220; Path=/alpha

So how would a developer access those headers from within a Javascript callout? The "normal" way to access a single-valued header is:

var hdr = context.getVariable('request.header.host'), 
    ctype = context.getVariable('request.header.content-type);

Accessing a multi-valued header in the same way returns a Java ArrayList to the Javascript. (Remember, the JS callout is running inside the Rhino script engine, which itself is hosted on the Java VM. So the values returned from such calls as context.getVariable() are actually set by Java code).

According to the doc page on variables in Apigee Edge , multi-valued headers can be accessed with a .values suffix. In Javascript, this would look like this:

 var hdr = context.getVariable('response.header.set-cookie.values');

If you then try to request hdr.toString(), you may get this error:

{
  "fault": {
    "faultstring": "Execution of Javascript-ExtractResponseCookies failed with error: Javascript runtime error: \"Access to Java class \"java.util.ArrayList\" is prohibited. (extractResponseCookies_js#11)\"",
    "detail": {
      "errorcode": "steps.javascript.ScriptExecutionFailed"
    }
  }
}

VERY unfriendly. In my opinion, this shouldn't happen, and I'm petitioning the product gods to change this behavior.

The good news is there is a way to avoid this.

UPDATE, 2019 Feb 26.

If you want to get the raw, string value of a header, that may or may not have commas within it, then you can use this form:

 var hdr = context.getVariable('response.header.set-cookie.values.string');

Just append ".values.string" to the "request.header.HEADERNAME" . This works for any header, request or response. For example, suppose a request header called "foo" which has a value "a=bar,b-123". Retrieving "request.header.foo.values" gives you the ArrayList thing I described above. Retrieving "request.header.foo.values.string" gives you the original string value of the header, "a=bar,b=123".

This also works in Condition statements (outside of JavaScript):

   <Step>
     <Name>SC-CheckAuthorization</Name>
     <Condition>request.header.foo.values.string = "a=bar,b=123"</Condition>
   </Step>

This is the older workaround I described previously (Don't Use This, it's too complicated and has no advantage over the previous method):

var hdr = context.getVariable('response.header.set-cookie.values')+'';

This coerces the value, which is an arraylist, to a string. The result looks something like "[value1, value2, value3]", so you need to deal with those square brackets if you decide to parse the value. For example:

// get the array of header values: 
var a = hdr.substring(1, hdr.length-1).split(',');

Pretty simple, eh? Thanks to @Mike Dunker for the tip. To carry the example just a little further, if you want just the first portion of each cookie (not the HttpOnly, nor the Path, nor the Expires, etc), then:

for (var i=0, L = a.length, oneHeader; i<L; i++) {
  oneHeader = a[i].split(';')[0].trim();
}

Ok, I hope this was helpful. In my next installment I will outline how to automatically file Birute's nag emails into a special invisible email folder.

thub.nodes.view.add-new-comment
edgejavascript
Add comment Show 7
10 |5000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by Apigeeks only
  • Viewable by the original poster
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image birute@google.com ♦♦   · Mar 31, 2015 at 04:58 PM 0
Link

@Dino definitely! and I think many people hanging out here would appreciate it.

Make us all proud :-)

avatar image vinay · Apr 07, 2016 at 03:22 PM 0
Link

Thanks for the post..After extracting the values(var a),is there a way to assign var 'a' in JS to use it further?

avatar image Dino ♦♦ vinay   · Apr 07, 2016 at 04:36 PM 0
Link

Hi Vinay, I would be glad to help you. But please as a new, toplevel question? And be specific about what you are trying to accomplish. I don't know what it means to say "is there way to assign var 'a'?" a is already assigned. so you'll have to elaborate.

but not HERE. In a new question please.

avatar image vinay Dino ♦♦ · Apr 07, 2016 at 08:43 PM 0
Link

Please check below post & help.

https://community.apigee.com/questions/21512/extract-comma-separated-header-value.html

avatar image Vikram Dayal · May 11, 2018 at 07:13 AM 0
Link

Is there a simi writeup for Java?

avatar image Dino-at-Google ♦♦ Vikram Dayal   · May 11, 2018 at 04:25 PM 0
Link

not that I know of. It should work in a more straightforward way in Java because a Java callout will receive a Collection<String> when retrieving the context variable like "request.header.name-of-multi-valued-header". And within Java you will be able to manipulate (read/write) that collection directly.

In JavaScript, you cannot access the native Java collection object, so there's a need to transform it implicitly into a string, and perform string manipulation. In Java that's not necessary.

If you have tried something and it's not working, and you cannot figure out why, please post a new question (don't reply to this with comment with a new question), and I'll see if I can help you.

avatar image Robert Johnson · Aug 03, 2019 at 08:47 AM 0
Link

hey @Dino-at-Google. Just noticed a couple things and wanted to confirm provide some updated info.

1) it appears that the following recommendation from above does NOT work for query params. Also, this property is not in the "flow variables" docs for the headers or query params.

 var qp = context.getVariable('request.queryparam.myparam.values.string');

2) this doesn't work (as noted in your original post) and perhaps the documentation should be updated with the workaround (item 3 below) until it is fixed?

var qp = context.getVariable('request.queryparam.myparam.values')

I couldn't get the above to coerce to a string until I saw your post about adding + ''

3) this does work

var sort = context.getVariable('request.queryparam.myparam.values')+'';

Obviously these two are meant to work together for looping through the params. I was able to get it all working using the following:

var count = context.getVariable('request.queryparam.myparam.values.count');
var qp  = context.getVariable('request.queryparam.myparam.values')+'';

//remove "[" and "]" from string and create the array
var params = qp.slice(1,-1).split(",");

//loop through the array
params.forEach(function(element, i) {
    //your code here
    //element has the value        
}

It would be great if we could have the following root issue fixed in a future release!

var qp = context.getVariable('request.queryparam.myparam.values')

Article

Contributors

avatar image avatar image

Follow this article

16 People are following this .

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Navigation

How to handle multi-value headers in Javascript?

Related Articles

Quick way to find the Developer App associated with a particular Consumer Key

Customized APIs by device - Belly

DEVOPS - Case for improved RMP removals

How to enable SSL on Apigee Edge?

Tutorial : Apigee Edge - Post Client Flow

Java 1.8.0_252 is incompatible with Apigee

Apigee as a SAML Identity Provider

Sample: Using Node.js caching with Edge policies

Asynchronous HTTP Requests in an API proxy

Apigee Edge Caching In Detail

  • Products
    • Edge - APIs
    • Insights - Big Data
    • Plans
  • Developers
    • Overview
    • Documentation
  • Resources
    • Overview
    • Blog
    • Apigee Institute
    • Academy
    • Documentation
  • Company
    • Overview
    • Press
    • Customers
    • Partners
    • Team
    • Events
    • Careers
    • Contact Us
  • Support
    • Support Overview
    • Documentation
    • Status
    • Edge Support Portal
    • Privacy Policy
    • Terms & Conditions
© 2021 Apigee Corp. All rights reserved. - Apigee Community Terms of Use - Powered by AnswerHub
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Create an article
  • Post an idea
  • Spaces
  • Product Announcements
  • General
  • Edge/API Management
  • Developer Portal (Drupal-based)
  • Developer Portal (Integrated)
  • API Design
  • APIM on Istio
  • Extensions
  • Business of APIs
  • Academy/Certification
  • Adapter for Envoy
  • Analytics
  • Events
  • Hybrid
  • Integration (AWS, PCF, Etc.)
  • Microgateway
  • Monetization
  • Private Cloud Deployment
  • 日本語コミュニティ
  • Insights
  • IoT Apigee Link
  • BaaS/Usergrid
  • BaaS Transition/Migration
  • Apigee-127
  • New Customers
  • Explore
  • Topics
  • Questions
  • Articles
  • Ideas
  • Badges