When we try to use apollo-link-rest in weixin mini program, we encounted a problem which has throw an error as below:
Headers is not defined
ReferenceError: Headers is not defined
As I found the source code in RestLink.ts, it does try to find the Headers, but absolutely, there is no Headers under weixin environment, so can anyone help to provide some hack or solutions to solve this issue? Much appreciate if you could help, thanks.
Hi @Janice1114, I’m unfamiliar with weixin, but maybe you can use a Headers Polyfill?
Often, if Headers is unavailable, Fetch will also be unavailable. So a polyfill that might work for both is this one: https://github.com/bitinn/node-fetch
Hi @fbartho , thanks for your quick reply. I've tried to use the polyfill to enable fetch headers, but still get the errors.
And I found that under weixin, it uses wx.request for the fetch, which does not support window related variable, so I'm afraid the polyfill won't work.
And may I know would there be any hack or implementations to help to skip the headers loop in source code of apollo-link-rest? Or could you please give some custom options to suit under different scenario?
You can use the customFetch
parameter to ApolloLinkRest in order to provide a wrapper function, this wrapper function can take the window-based-headers from the Polyfill, and flatten it into a traditional object Hash.
Something like the following (untested, written in my browser):
function customFetch(url, options) {
const headers = options.headers.entries().reduce((accumulator, h) => { accumulator[h[0]] = h[1]; return accumulator;}, {})
return fetch(url, {…options, headers});
}
// Elsewhere: new RestLink({ customFetch, ...
So much appreciate for your kindly response, I will try to use this polyfill in weixin development.
And as I read the source code in RestLink.ts, it will try to access the Headers, which is not available in weixin. It could assign the variables in global
.
So I wonder if any custom or overrided settings, could be applied during RestLink constructor process?
Best regards again for your so wonderful tips.
Hi @fbartho ,to fix this issue in weixin and related special browser, I've create a PR as below:
Headers issue fix
Could you please help and review whether the code PR is available to merge into master?
Much appreciate and thanks a lot if that could help.
I have the same problem in "next": "^9.0.3"
I'm also having this problem with next, version ^8.1.0
. For my graph API I use isomorphic-unfetch
, version ^3.0.0
to polyfill like so:
import fetch from 'isomorphic-unfetch'
const graphLink = createHttpLink({ uri, fetch })
But using the same package to polyfill with the rest link did not work:
const restLink = new RestLink({
uri,
customFetch: fetch,
})
I also tried node-fetch
using your customFetch method:
import fetch from 'node-fetch'
function customFetch(url, options) {
const headers = options.headers.entries().reduce((accumulator, h) => {
accumulator[h[0]] = h[1]
return accumulator
}, {})
return fetch(url, { ...options, headers })
}
const restLink = new RestLink({
uri: CONTENTFUL_CONTENT_DELIVERY_API,
customFetch,
})
In both cases I got ReferenceError: Headers is not defined
when running next in dev mode.
Love the idea here, would love if you could provide some direction for how to implement in server environments. Thanks!
You can polyfill the Headers API while still using your own customFetch API!
Let me know if you would like some sample code there, but I’m confident this is doable without too much hassle. I’m not at my computer just this minute.
@fbartho Some sample code would be great when you have a chance! I took a stab at it, but wasn't successful. Thanks!
import * as Polyfillheaders from 'fetch-headers'
import fetch from 'isomorphic-unfetch'
// hook in the Headers polyfill for your environment!
global.Headers = global.Headers || Polyfillheaders;
function customFetch(url, options) {
const headers = options.headers.entries().reduce((accumulator, h) => {
accumulator[h[0]] = h[1]
return accumulator
}, {})
return fetch(url, { ...options, headers })
}
const restLink = new RestLink({
uri: CONTENTFUL_CONTENT_DELIVERY_API,
customFetch,
})
Something like the above might do the trick @2wheelcoder
Thanks! I'll report back here after I have a chance to give this a shot.
@fbartho Hi! I'm facing this problem on ios 9.3.5.I tried import the fetch-headers
polyfill but not work.
I found that the header instance from fetch-headers
doesn't have the forEach
method(see below).
Is there any other solutions?
@fbartho Hi! I'm facing this problem on ios 9.3.5.I tried import the
fetch-headers
polyfill but not work.
I found that the header instance fromfetch-headers
doesn't have theforEach
method(see below).
Is there any other solutions?
I solved this problem by using the fetch polyfill.
I'm going to close this, because I believe we can resolve this with a polyfill on the App-side, and we don't want to make the polyfill a dependency of this repository.
I have not been able to solve this with a polyfill. I've tried isomorphic-fetch, isomorphic-unfetch, fetch-headers, etc and always end up with an issue about current.forEach
not being defined or TypeError: Right-hand side of 'instanceof' is not an object
. Any help?
@VinSpee Have you ever tried this fetch polyfill.
@lintuming yes but it doesn’t work on the server.
@VinSpee Maybe you can use this,it seems they have the forEach
method.
Hope this work.
@lintuming thanks for trying to help. With that one, I get:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
seems to be a tangled web of problems 🤣
@VinSpee Sorry,I have no idea why this happen.But i think this could help:
https://stackoverflow.com/questions/7042340/error-cant-set-headers-after-they-are-sent-to-the-client
Here's what ended up working for me:
import clientFetch from 'unfetch';
import serverFetch, { Headers as ServerHeaders } from 'node-fetch';
const client = typeof document !== 'undefined';
global.Headers = client ? global.Headers : ServerHeaders;
const customFetch = client ? clientFetch : serverFetch;
const acmeLink = new JsonApiLink({
…
credentials: 'same-origin',
customFetch,
});
@VinSpee i am facing same issue and i tried to fix this issue with your solution but i am not succeeded.
Can you please share your working code
Thanks @VinSpee —this was exactly what I needed
I was able to fix this issue by using custom fetch
import fetch from "isomorphic-fetch"
const restLink = new RestLink({
uri: "https://...",
customFetch: fetch,
headers: {
"Content-Type": "application/json",
},
})
@VinSpee 's solution worked for me for a Gatsby JS application as well.
Most helpful comment
Here's what ended up working for me: