How should I implement the proxy API
Closed this issue · 1 comments
KingerLeen commented
Thank you for maintaining this project.
I can now use this project to load a local HTML (I only need to use it on an Android device), but using APIs for local HTML will result in CORS.
This service is 127.0.0.1, but the requested API should be www.myserver.com.
There are two solutions to this problem
The first solution is: WebView allows CORS:
<WebView
allowsBackForwardNavigationGestures={true}
originWhitelist={["*"]}
mixedContentMode="always"
domStorageEnabled={true}
allowFileAccess={true}
allowsFullscreenVideo
forceDarkOn
allowFileAccessFromFileURLs={true}
allowUniversalAccessFromFileURLs={true}
javaScriptEnabled
/>
This time, HTML Sent requests is: http://www.myserver.com/api/xxxxx
But it doesn't work
The second solution is: StaticServer proxy API
extraConfig: `
$HTTP["url"] =~ "^/api" {
proxy.server = ( "/api" => (( "host" => "www.myserver.com" )))
}
`,
This time, HTML Sent requests is: /api/xxxxx
But it doesn't work too.
Here is my source code
import React, { useEffect, useRef, useState } from "react";
import {
Platform,
SafeAreaView,
StatusBar,
StyleSheet,
Linking,
View,
} from "react-native";
import { Colors } from "react-native/Libraries/NewAppScreen";
import {
copyFileAssets,
readFile,
readFileAssets,
unlink,
} from "@dr.pogodin/react-native-fs";
import WebView, { WebViewNavigation } from "react-native-webview";
import Server, {
STATES,
resolveAssetsPath,
} from "@dr.pogodin/react-native-static-server";
export default function App() {
const webView = useRef<WebView>(null);
const [theme, setTheme] = useState<string>("light");
const isDarkMode = theme === "dark";
const backgroundStyle = {
backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
flex: 1,
};
const [origin, setOrigin] = useState<string>("");
console.log(origin);
useEffect(() => {
const fileDir = resolveAssetsPath("webroot");
let server: null | Server = new Server({
fileDir,
hostname: "127.0.0.1",
port: 3000,
stopInBackground: true,
errorLog: {
conditionHandling: true,
fileNotFound: true,
requestHandling: true,
requestHeader: true,
requestHeaderOnError: true,
responseHeader: true,
timeouts: true,
},
extraConfig: `
$HTTP["url"] =~ "^/api" {
proxy.server = ( "/api" => (( "host" => "www.myserver.com" )))
}
`,
});
const serverId = server.id;
(async () => {
if (Platform.OS === "android") {
let extract = true;
try {
const versionD = await readFile(`${fileDir}/version.text`, "utf8");
const versionA = await readFileAssets("webroot/version.text", "utf8");
if (versionA === versionD) {
extract = false;
} else {
await unlink(fileDir);
}
} catch {}
if (extract) {
console.log("Extracting web server assets...");
await copyFileAssets("webroot", fileDir);
}
}
server?.addStateListener((newState, details, error) => {
console.log(
`Server #${serverId}.\n`,
`Origin: ${server?.origin}`,
`New state: "${STATES[newState]}".\n`,
`Details: "${details}".`
);
if (error) console.error(error);
});
const res = await server?.start();
if (res && server) {
setOrigin(res);
}
})();
return () => {
(async () => {
server?.stop();
server = null;
setOrigin("");
})();
};
}, []);
const handleMessage = (str = "{}") => {
let obj = {} as any;
try {
obj = JSON.parse(str);
} catch {
obj = {};
}
console.log("handleMessage", obj);
switch (obj.key) {
case "theme":
setTheme(obj.value);
break;
default:
break;
}
};
return (
<SafeAreaView style={backgroundStyle}>
<StatusBar
barStyle={isDarkMode ? "light-content" : "dark-content"}
backgroundColor={backgroundStyle.backgroundColor}
/>
<View style={styles.webview}>
<WebView
allowsBackForwardNavigationGestures={true}
originWhitelist={["*"]}
mixedContentMode="always"
domStorageEnabled={true}
allowFileAccess={true}
allowsFullscreenVideo
forceDarkOn
allowFileAccessFromFileURLs={true}
allowUniversalAccessFromFileURLs={true}
javaScriptEnabled
cacheMode="LOAD_NO_CACHE"
onMessage={(event: any) => {
const message = event.nativeEvent.data;
handleMessage(message);
}}
onShouldStartLoadWithRequest={(request: any) => {
const load = request.url.startsWith(origin);
if (!load) {
Linking.openURL(request.url);
}
return load;
}}
ref={webView}
source={
origin
? { uri: `${origin}/?insert=1&runerType=AndroidRN` }
: { html: "" }
}
/>
</View>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
text: {
marginTop: 8,
fontSize: 18,
fontWeight: "400",
},
title: {
fontSize: 24,
fontWeight: "600",
},
webview: {
flex: 1,
},
});
birdofpreyru commented
Hey @KingerLeen , perhaps you should revisit how CORS work — the browser behaves according to CORS (HTTP) headers of the main HTML document, thus I guess you just should use SetEnv module to set correct CORS headers to whitelist your API domain for JS scripts in your page.