Using WebView in a React Native application allows us to reuse already built web pages.
HTTP Headers are name/value pairs that appear in both request and response messages. The purpose of headers is to supply the web server with additional information and control how content is returned.
In React Native, while opening web pages via WebView Component, we can pass headers to the HTTP request. Refer to our previous blog for more on this.
1<WebView 2 source={{ 3 uri: "http://localhost:3000", 4 headers: { "custom-app-header": "react-native-ios-app" }, 5 }} 6/>
But there is a bug. On subsequent requests from inside the WebView, the headers are not passed in the request.
First, let's try to understand by recreating the bug. We have created a simple node server which will act as the backend for the application and log the request along with the custom header.
Here is our server.js
1var http = require("http"); 2var port = 9000; 3 4function logRequest(request) { 5 console.log("Processing request for: ", request.url); 6 console.log("Custom Header: ", request.headers["custom-app-header"]); 7 console.log("Request Processed\n"); 8} 9 10http 11 .createServer(function (request, response) { 12 response.writeHead(200, { "Content-Type": "text/html" }); 13 switch (request.url) { 14 case "/": 15 response.write( 16 "<html><body>Welcome<a href='/bye'>Bye</a></body></html>" 17 ); 18 logRequest(request); 19 break; 20 case "/bye": 21 response.write("<html><body>Bye<a href='/'>Welcome</a></body></html>"); 22 logRequest(request); 23 break; 24 default: 25 break; 26 } 27 response.end(); 28 }) 29 .listen(port);
As we can see, the welcome page has a link to bye and vice versa. Let's start the node server by running node server.js.
When we run the app on the simulator, the welcome page opens up, and in the server log, we can verify that the request header is being passed.
1Processing request for: / 2Custom Header: react-native-ios-app 3Request Processed
But when we click on the Bye link from the Welcome page, the server doesn't receive the request header, which can be verified from the log.
1Processing request for: /bye 2Custom Header: undefined 3Request Processed
And it can be verified again that for any subsequent clicks the request header does not get passed. We can click on Welcome and check the log again.
1Processing request for: / 2Custom Header: undefined 3Request Processed
We recently encountered this bug and created an issue here. Until the issue is fixed, we have found a workaround.
Workaround
WebView provides a prop onLoadStart which accepts a function that is invoked when the WebView starts loading.
We can use this prop to know when a link is clicked and then re-render the WebView component with the new url. Re-rendering the WebView component will load the page as if it's the first page and then the request headers would be passed.
We know that in React, a component re-renders itself when any of its state changes. The only thing which changes here is the url, so let's move the url to a state and initialize it to the Welcome page which is the root of the application. And then use the onLoadStart prop to change the url state to the clicked url.
Here's the new code.
1class testApp extends Component { 2 state = { 3 url: "http://localhost:3000", 4 }; 5 6 render() { 7 return ( 8 <WebView 9 onLoadStart={(navState) => 10 this.setState({ url: navState.nativeEvent.url }) 11 } 12 source={{ 13 uri: this.state.url, 14 headers: { "custom-app-header": "react-native-ios-app" }, 15 }} 16 /> 17 ); 18 } 19}
Now when we run the app, we can verify in the backend that the request headers are being sent even when we click on Bye link.
1Processing request for: /bye 2Custom Header: undefined 3Request Processed 4 5Processing request for: /bye 6Custom Header: react-native-ios-app 7Request Processed
One thing to note here is that, when we click on the Bye link, the request is not intercepted from reaching the server. We are just resending the request by means of a component re-render with the new url.
Hence in the log, we see two requests. First request took place when user clicked on the link, and the second request occurred when the component got re-rendered with the required request headers.
This workaround might help us to pass the request headers which we intend to send to the backend server until the issue gets fixed.