Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible to change header info for tile request? #2091

Closed
newmanw opened this issue Oct 11, 2013 · 20 comments
Closed

Possible to change header info for tile request? #2091

newmanw opened this issue Oct 11, 2013 · 20 comments

Comments

@newmanw
Copy link
Contributor

newmanw commented Oct 11, 2013

I need to access tile servers which require a token to be passed. Is there any way to intercept the tile request so that I can add something to the header before the request is made. I.E. it would be nice if I could listen for a pre-tile request, via an event, mess with the headers and send the request on its way.

@mourner
Copy link
Member

mourner commented Oct 11, 2013

Hmm... Is there a way to do that in HTML? I mean, how would you load an image with custom headers in general, not talking about Leaflet?

@newmanw
Copy link
Contributor Author

newmanw commented Oct 12, 2013

Good point! Digging deeper I see what is going on. And yes you are correct I do not think there is a way to mod headers unless you are making an AJAX request. Most APIs allow access tokens to also be passed in the url as a query param. I will look more into that.

If possible to pass as params in my case I think I can just extend TileLayer to pass the param information that I need. I can create an extension that essentially adds query params to the TileLayer (TileLayerQueryParam or something). Have you come across any situations in which TileLayer would need to pass query params? I.E. extension is fine, but wondering if this should be part of TileLayer.

@mourner
Copy link
Member

mourner commented Oct 12, 2013

Yep, adding query params is much easier. :)

@mourner mourner closed this as completed Oct 12, 2013
@zhenyanghua
Copy link

adding as query params is fine, but it exposes the token in the request url. when implementing a OAuth 2.0, the suggestion is to write the token into the header. This issue should be a new pull request.

@rrameshkumar76
Copy link

rrameshkumar76 commented May 15, 2017

This feature would be great for OAuth 2.0 to add the authorization header.

@perliedman
Copy link
Member

@zhenyanghua @rrameshkumar76 as mentioned above, TileLayer is just an img tag, and to out knowledge there is no way to set custom headers for an image tag.

Having said that, you can load tiles any way you want (like using AJAX) if you extend GridLayer. There's some pretty good examples on how to do things like that in the Extending Leaflet, New Layers tutorial.

@rrameshkumar76
Copy link

rrameshkumar76 commented May 15, 2017

Thanks @perliedman for the answer and the explanation.
I was able to extend L.TileLayer.WMS and override the createTile method where i made a ajax call to get the tile image with headers.

@SunnyMittal
Copy link

Hi Ramesh Kumar, is it possible for you to share the extended WMS class for reference ?
Thanks heaps

@rrameshkumar76
Copy link

rrameshkumar76 commented May 19, 2017

@SunnyMittal I used superagent for ajax, replace it as needed.

L.TileLayer.WMS_Headers = L.TileLayer.WMS.extend({
  createTile(coords, done) {
    const url = this.getTileUrl(coords);
    const img = document.createElement('img');
    superagent
      .get(url)
      .set(‘header’, ‘header value’)
      .responseType('blob')
      .then((response) => {
        img.src = URL.createObjectURL(response.body);
        done(null, img);
      });
    return img;
  }
});

L.tileLayer.wms_headers = (url, options) => new L.TileLayer.WMS_Headers(url, options);

@SunnyMittal
Copy link

@rrameshkumar76 thanks it helped :)

@ticinum-aerospace
Copy link

ticinum-aerospace commented Dec 21, 2018

based on @rrameshkumar76 anwser, I built a super simple plugin.
Hope you will enjoy it.

@AB-Kent
Copy link

AB-Kent commented Sep 3, 2019

If any one wants to add headers to L.TileLayer instead of L.TileLayer.WMS, this is possible by a simple modification of @ticinum-aerospace 's plugin. Just change the base class from L.TileLayer.WMS to L.TileLayer and rename the new class and function appropriately.

@jaq316
Copy link

jaq316 commented Feb 19, 2020

I've modified @ticinum-aerospace 's plugin for L.TileLayer instead of L.TileLayer.WMS here: https://github.com/jaq316/leaflet-header/blob/master/index.js

@bkanuka
Copy link

bkanuka commented Feb 12, 2021

Are there any thoughts or plans on integrating this into the core library? I can't imagine it would be a breaking change because by default you just wouldn't send extra headers.

@johnd0e
Copy link
Collaborator

johnd0e commented Feb 12, 2021

Are there any thoughts or plans on integrating this into the core library?

No plans.
But anyone can propose this in PR.

@JoseMeneghetti
Copy link

JoseMeneghetti commented Jan 15, 2024

I'm using old versions of react-leaflet in my project, so I could reach this lib old lib : react-leaflet-extendable and I did it by extending my TileLayer component.

"react-leaflet": "2.4.0",
"react-leaflet-extendable": "1.0.2",
import { ExtendableTileLayer } from "react-leaflet-extendable";
import { withLeaflet } from "react-leaflet";
import { TileLayer as LeafletTileLayer } from 'leaflet'

async function fetchImage(url, callback, headers, abort) {
  const controller = new AbortController();
  const signal = controller.signal;
  if (abort) {
    abort.subscribe(() => {
      controller.abort();
    });
  }
  const f = await fetch(url, {
    method: "GET",
    headers: headers,
    mode: "cors",
    signal: signal
  });
  const blob = await f.blob();
  callback(blob);
}

const LWMSTileLayerWithHeader = LeafletTileLayer.WMS.extend({
  initialize: function (url, options) {
    const { headers, abort, results, ...props } = options;
    LeafletTileLayer.WMS.prototype.initialize.call(this, url, props);
    this.headers = headers;
    this.abort = abort;
    this.results = results;
  },
  createTile(coords, done) {
    const url = this.getTileUrl(coords);
    const img = document.createElement("img");
    img.setAttribute("role", "presentation");

    fetchImage(
      url,
      resp => {
        const reader = new FileReader();
        reader.onload = () => {
          img.src = reader.result;
          if (this.results) {
            this.results.next(reader.result);
          };
        };
        reader.readAsDataURL(resp);
        done(null, img);
      },
      this.headers,
      this.abort
    );
    return img;
  }
});

class NewTileComponent extends ExtendableTileLayer {
  componentDidMount(...attributes) {
    super.componentDidMount(...attributes);
  }

  createLeafletElement(props) {
    const options = this.getOptions(props);

    // Insert the headers here
    const headers = {
      "Custom-Header": "Custom-Value",
      // add more headers as necessary
    };

    // Combine the headers with the old options
    const mergedOptions = {
      ...options,
      headers: {
        ...options.headers,
        ...headers
      }
    };
    return new LWMSTileLayerWithHeader(props.url, mergedOptions);
  }

  createTile(coords, done) {
    const url = this.getTileUrl(coords);
    const img = document.createElement("img");
    img.setAttribute("role", "presentation");

    fetchImage(
      url,
      resp => {
        const reader = new FileReader();
        reader.onload = () => {
          img.src = reader.result;
          if (this.results) {
            this.results.next(reader.result);
          };
        };
        reader.readAsDataURL(resp);
        done(null, img);
      },
      this.headers,
      this.abort
    );
    return img;
  }

  updateLeafletElement(fromProps, toProps) {
    super.updateLeafletElement(fromProps, toProps);
    if (toProps.url !== fromProps.url) {
      this.leafletElement.setUrl(toProps.url);
    }
  }
}

export default withLeaflet(NewTileComponent);

@smartm0use
Copy link

based on @rrameshkumar76 anwser, I built a super simple plugin. Hope you will enjoy it.

I have forked it here: https://github.com/smartm0use/leaflet-wms-header-opt

updated source code according to latest dist original version;
made abort and results parameters as optional;
updated rxjs and typescript versions

@mariochermes
Copy link

mariochermes commented May 17, 2024

I don't know quite the why - as it isn't referenced in the docs - but just adding the authkey to the options parameter works for me:

EDIT: as @IvanSanchez mentioned, https://leafletjs.com/reference.html#tilelayer-wms provides the explanation on why the following works.

layer: L.tileLayer.wms(url, {
                attribution: '',
                layers: WORKSPACE:LAYER_NAME,
                format: 'image/png',
                transparent: true,
                authkey: authkey
              } as any).on('tileload', this.loadingEventHandler)

@IvanSanchez
Copy link
Member

I don't know quite the why - as it isn't referenced in the docs

@mariochermes See https://leafletjs.com/reference.html#tilelayer-wms, specifically the bit that says «If any custom options not documented here are used, they will be sent to the WMS server as extra parameters in each request URL.»

@mariochermes
Copy link

I don't know quite the why - as it isn't referenced in the docs

@mariochermes See https://leafletjs.com/reference.html#tilelayer-wms, specifically the bit that says «If any custom options not documented here are used, they will be sent to the WMS server as extra parameters in each request URL.»

Thanks for the info, I didn't see that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests