a web dev proxy server that has implement request cors and cookie cors, base on shelf_proxy
Features
- Modify response headers and cookie for cors in web dev
Getting started
step1
Define your target host and local proxy host and port in a dart file ,just like :
class LocalProxyConfig{
static String targetUrl = 'https://navi-api.xxx.tech';
static const String localHost = 'localhost';
static const int localPort = 8033;
static const String localProxyUrlWeb = "http://$localHost:$localPort";
}
step2
define a main method in another dart file:
import 'package:web_dev_proxy/src/shelf_proxy_for_web_dev.dart';
import 'proxy_web_local_config.dart';
Future<void> main() async {
await startLocalProxyServerForWebDebug(LocalProxyConfig.localHost,LocalProxyConfig.localPort,LocalProxyConfig.targetUrl,true);
}
step3
Run the main method in step2
Will print:
Proxying at http://localhost:8033 for https://navi-api.xxx.tech
step4
use LocalProxyConfig.localProxyUrlWeb as your base url in project when platform is web.
what did we do in the proxy
modify headers to allow request cros
just like what you will do in nginx when release in web
// 修改响应头
//有时后台写了Access-Control-Allow-Origin,那么server.defaultResponseHeaders的设置就会无效
//if("OPTIONS" == (clientResponse?.request?.method??"")){
Map<String, String> headers = clientResponse.headers;
//不能同时多个
headers.remove('access-control-allow-origin');
headers.remove('access-control-allow-methods');
headers.remove('access-control-allow-headers');
headers.remove('access-control-expose-headers');
headers.remove('access-control-max-age');
headers.remove('access-control-allow-credentials');
//你请求什么,就允许什么
//access-control-request-headers 这个是chrome加了,所以在request!.headers里取不到
//Request header field app-version is not allowed by Access-Control-Allow-Headers in preflight response.
//Map<String, String> reqeustHeaders = clientResponse!.request!.headers!;
String headerStr = clientResponse!.request!
.headers['access-control-request-headers'].toString();
//预检请求不会携带额外的header,所以下面拼接header没有鸟用, 要用access-control-request-headers取
//reqeustHeaders.forEach((key, value) { headerStr = headerStr+","+key; });
//access-control-request-headers
if (headerStr == "null") {
headerStr = "*";
}
clientResponse.headers['Access-Control-Allow-Headers'] = headerStr;
//clientResponse.headers['Access-Control-Allow-Headers'] = "*";//预检请求里,['Access-Control-Allow-Credentials'] = 'true'时 不能用*
clientResponse.headers['Access-Control-Allow-Methods'] = "*"; //GET,POST,PUT,OPTIONS
clientResponse.headers['Access-Control-Expose-Headers'] = headerStr;
clientResponse.headers['Access-Control-Max-Age'] = '36000'; //如果chrome开启了禁用缓存,那么每次都会发预检请求
clientResponse.headers['Access-Control-Allow-Credentials'] = 'true';
//预检请求: 设置了-Allow-Credentials'] = 'true'时,两个限制:
// Access-Control-Allow-Origin'] 不能为 "*" -Allow-Headers'] = "*"
//clientResponse.headers['Access-Control-Allow-Origin'] = "*";
String original = clientResponse!.request!.headers["Referer"].toString();
if(original == "null"){
original = "*";
}
if (original.endsWith("/")) {
original = original.substring(0, original.length - 1);
}
clientResponse.headers['Access-Control-Allow-Origin'] = original;
//The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
// The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
modify set-cookie header
void transferCookies(http.StreamedResponse clientResponse,String localHost) {
String? cookie = clientResponse.headers['set-cookie'];
if (cookie == null || cookie.isEmpty) {
return;
}
//服务器要发送多个 cookie,则应该在同一响应中发送多个 Set-Cookie 标头。
Cookie cookie2 = Cookie.fromSetCookieValue(cookie);
cookie2.secure = true;
cookie2.httpOnly = false;
cookie2.domain = localHost;
clientResponse.headers['set-cookie'] = cookie2.toString() + ";SameSite=None;";
print("reset set-cookie header from $cookie to \n ${clientResponse.headers['set-cookie']}\n");
}
Thanks
Libraries
- web_dev_proxy
- Support for doing something awesome.