简体   繁体   English

如何使用 Apache 正确配置反向代理,以用于跨域 AJAX?

[英]How to correctly configure a reverse proxy with Apache, to be used for cross-domain AJAX?

Needing to develop a web application that at the same time is highly dependent on an API but at the same time cannot reside on the same domain as the API itself, it's been quite tricky getting around the "Same Origin Policy" when making asynchronous HTTP requests (AJAX).需要开发一个 Web 应用程序,该应用程序同时高度依赖 API 但同时不能与 API 本身驻留在同一域中,在发出异步 HTTP 请求时绕过“同源策略”非常棘手(阿贾克斯)。 At one point, I was recommended to install WAMP on my computer (running Windows 7) and to configure a reverse proxy with Apache.有一次,我被建议在我的计算机上安装 WAMP(运行 Windows 7)并使用 Apache 配置反向代理。 The same person gave me the Apache directives bellow that I added to the httpd.conf file, after telling me to create an alias for the IP 127.0.0.1 named dev , within the file at c:\\windows\\system32\\drivers\\etc\\hosts (which I did):在告诉我在c:\\windows\\system32\\drivers\\etc\\hosts的文件中为名为dev的 IP 127.0.0.1 创建别名之后,同一个人给了我下面添加到httpd.conf文件的 Apache 指令c:\\windows\\system32\\drivers\\etc\\hosts (我做了):

LoadModule headers_module modules/mod_headers.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_connect_module modules/mod_proxy_connect.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule ssl_module modules/mod_ssl.so

Listen 127.0.0.1:8080
ProxyRequests off

<Proxy *>
                Order deny,allow
                Deny from all
                Allow from 127.0.0.1
</Proxy>

<VirtualHost dev:8080>
                ProxyPass / https://app.somesite.com:5002/
                ProxyPassReverse / https://app.somesitecom:5002/
                ProxyPassReverseCookieDomain app.somesite.com dev
                Header edit Location ^https://dev(:8080)?(.+)$ http://dev$1$2
                Header edit Set-Cookie "(^.+); secure; HttpOnly$" "$1; HttpOnly"
                SSLProxyEngine on
    SSLProxyVerify none
</VirtualHost>

Since I'm a complete novice when it comes to configuring servers, I simply pasted the directives and fortunately enough, the proxy worked.由于我在配置服务器方面完全是新手,因此我只是粘贴了指令,幸运的是,代理工作正常。 It returns the correct response from the API when I use the browser's address bar to access, for example, http://dev:8080/a/w/currencies .当我使用浏览器的地址栏访问时,它会从 API 返回正确的响应,例如http://dev:8080/a/w/currencies

Unfortunately though, an AJAX request to the same URL (code bellow) makes Chrome give me the XMLHttpRequest cannot load http://dev:8080/a/w/currencies. Origin http://dev is not allowed by Access-Control-Allow-Origin.不幸的是,对同一 URL 的 AJAX 请求(代码如下)使 Chrome 给我XMLHttpRequest cannot load http://dev:8080/a/w/currencies. Origin http://dev is not allowed by Access-Control-Allow-Origin. XMLHttpRequest cannot load http://dev:8080/a/w/currencies. Origin http://dev is not allowed by Access-Control-Allow-Origin. error.错误。

$.ajax({
    url: "http://dev:8080/a/w/currencies",
    type: "GET",
    dataType: "json",
    data: {

    },
    success: function(data){
        console.log(data);
    }
}); 

So what must still be done in order for this proxy to work with AJAX?那么,为了让这个代理与 AJAX 一起工作,还必须做什么? I've been told something about an alias directive, but not specific and clear enough, so it didn't make much sense to my inexperienced brain.有人告诉我一些关于alias指令的事情,但不够具体和清晰,所以对我没有经验的大脑来说没有多大意义。

PS: Also, I've been told " the problem is that you're getting the files from dev:80 and ajaxing to dev:8080 ". PS:另外,有人告诉我“问题是你从 dev:80 获取文件并 ajaxing 到 dev:8080 ”。 Given my inexperience, neither this makes much sense.鉴于我的经验不足,这都没有多大意义。

You are having a server with a public IP and apache is running on it.Now you want to host your applications on LAN and also want them to be accessible on internet the important part is these applications are still running on the machines on LAN.您拥有一台带有公共 IP 的服务器,并且 apache 正在其上运行。现在您想在 LAN 上托管您的应用程序,并希望它们可以在 Internet 上访问,重要的是这些应用程序仍在 LAN 上的机器上运行。

                           |--------------192.168.1.3
                           |            (internal3.example.com)
                           |
                           |--------------192.168.1.4
                           |            (internal4.example.com)
  (Public IP )             |
            A--------------|
(reverse proxy server)     |
  (192.168.1.25)           |
example.com                |
                           |--------------192.168.1.1
                           |            (internal1.example.com)
                           |
                           |--------------192.168.1.2
                           |            (internal2.example.com)

I am using Ubuntu to host Apache the vhost definition in case of Debian based systems the definiton of websites is done on我正在使用 Ubuntu 来托管 Apache 虚拟主机定义,以防基于 Debian 的系统网站的定义是在

/etc/apache2/sites-enabled/*.conf /etc/apache2/sites-enabled/*.conf

where *conf corresponds to其中 *conf 对应于

internal1.conf internal2.conf internal3.conf internal4.conf internal1.conf internal2.conf internal3.conf internal4.conf

The vhost definition of each of these sites will be as follows每个站点的 vhost 定义如下

/etc/apache2/sites-enabled/internal1.example.conf /etc/apache2/sites-enabled/internal1.example.conf

<virtualhost *:80>
    ServerAdmin webmaster@localhost
    ServerName internal1.example.com
    ProxyRequests off
    <proxy *>
        Order deny,allow
        Allow from all
    </proxy >
    ProxyPass / http://192.168.1.1/
    ProxyPassReverse / http://192.168.1.1/ 
</VirtualHost>

/etc/apache2/sites-enabled/internal2.example.conf /etc/apache2/sites-enabled/internal2.example.conf

<virtualhost *:80>
      ServerAdmin webmaster@localhost
      ServerName internal2.example.com
      ProxyRequests off
      <proxy *>
      Order deny,allow
      Allow from all
      </proxy >
      ProxyPass / http://192.168.1.2/
      ProxyPassReverse / http://192.168.1.2/
</VirtualHost >

/etc/apache2/sites-enabled/internal3.example.conf /etc/apache2/sites-enabled/internal3.example.conf

<virtualhost *:80>
      ServerAdmin webmaster@localhost
      ServerName internal3.example.com
      ProxyRequests off
      <proxy *>
      Order deny,allow
      Allow from all
      </proxy >
      ProxyPass / http://192.168.1.3/
      ProxyPassReverse / http://192.168.1.3/
</VirtualHost >

/etc/apache2/sites-enabled/internal4.example.conf /etc/apache2/sites-enabled/internal4.example.conf

<virtualhost *:80>
    ServerAdmin webmaster@localhost
    ServerName internal4.example.com
    ProxyRequests off
    <proxy *>
        Order deny,allow
        Allow from all
    </proxy>
    ProxyPass / http://192.168.1.4/
    ProxyPassReverse / http://192.168.1.4/
</VirtualHost>

Note in all of the above vhost definitions I have dropped the options of Log files.请注意,在上述所有 vhost 定义中,我都删除了日志文件的选项。 So if you apply to a production server add them in each of the vhost file.因此,如果您应用于生产服务器,请将它们添加到每个 vhost 文件中。 Above is just to give you a clear cut example as how it can be working.以上只是给你一个清晰的例子,说明它是如何工作的。 I run a very complex Apache setup so above is just a small example to help you.我运行了一个非常复杂的 Apache 设置,所以上面只是一个帮助你的小例子。

Now coming to Ajax part of your question现在来到你问题的 Ajax 部分

in chrome press Ctrl+Shift+I you will see where exactly the application is broken, it will give you some clue, ( issue the request from a machine different from the machine on which you are developing web application ) also if you can look at apache logs if the request from http://sample page which has ajx api actually reached your apache server that will give you more hint, if the proxy is forwarding your request correctly, post the HTTP HEADERS by using some tool in firefox like live_http in condition when there was no request and the condition when the request was made by the application that way observing the headers one can help you if the request reached the server behind the reverse proxy,also check the logs of server which is running reverse proxy if the request from web reached it or not and if the request reached what is the URL that was requested.This will give you a clue,在 chrome 中按 Ctrl+Shift+I,您将看到应用程序的确切损坏位置,它会给您一些线索,(从与您正在开发 Web 应用程序的机器不同的机器发出请求),如果您也可以查看如果来自具有 ajx api 的http://sample页面的请求实际上到达了您的 apache 服务器,这会给您更多提示,如果代理正确转发您的请求,请使用 firefox 中的一些工具发布 HTTP HEADERS,例如 live_http没有请求时的条件和应用程序发出请求时的条件,如果请求到达反向代理后面的服务器,则观察标头可以帮助您,如果请求到达反向代理服务器,请检查运行反向代理的服务器的日志来自 web 的请求是否到达了它,如果请求到达了请求的 URL。这会给你一个线索,

and for development purpose in your .conf files disable the rewrite rules for some time to test ,do it one by one.并且出于开发目的,在您的 .conf 文件中禁用重写规则一段时间以进行测试,一一进行。

The problem here is that the browser is trying to protect you from getting pwned by random javascript placed on some web page.这里的问题是浏览器试图保护您免受放置在某个网页上的随机 javascript 的攻击。 If it would let all javascript to run in the same context you would lose you Facebook sessions cookies or some other data to bad guys.如果它让所有 javascript 在相同的上下文中运行,你就会失去 Facebook 会话 cookie 或其他一些数据给坏人。

In this case the culprit could be something so simple as Chrome does not consider 'dev' to be a Fully Qualified Domain Name so it will fail the same origin test.在这种情况下,罪魁祸首可能很简单,因为 Chrome 不认为“dev”是完全合格的域名,因此它将无法通过同源测试。 Other reason might be that at some point you are getting stuff from app.somesite.dev and at some point you send requests to 'dev'其他原因可能是在某些时候你从 app.somesite.dev 获取东西,在某些时候你向“dev”发送请求

The servers don't care what they send and it is the browser you need to fool to believe everything is coming from the same host服务器不在乎他们发送什么,它是你需要愚弄的浏览器相信一切都来自同一个主机

  1. I would replace 'dev' in the hosts file with dev.example.com 127.0.0.1我会用 dev.example.com 127.0.0.1 替换主机文件中的“dev”
  2. I would make sure everything coming out of the Apache proxy only refers to dev.example.com no matter from which server it comes我会确保来自 Apache 代理的所有内容都只引用 dev.example.com,无论它来自哪个服务器
  3. Only use dev.example.com in your code仅在您的代码中使用 dev.example.com

If all else fails you could add a HTTP header 'Access-Control-Allow-Origin: *' to allow any origin, but I would not use this except just in dev-environments.如果所有其他方法都失败了,您可以添加一个 HTTP 标头 'Access-Control-Allow-Origin: *' 以允许任何来源,但除了在开发环境中之外,我不会使用它。

PS.附注。 Even if you get javascript from example.com:80 that javascript can't even call example.com:443 or javascript from example.com cannot make xmlhttprequests to dev.example.com即使您从 example.com:80 获得 javascript,该 javascript 甚至无法调用 example.com:443 或来自 example.com 的 javascript 也无法向 dev.example.com 发出 xmlhttprequests

on 127.0.0.1, your html code should be:在 127.0.0.1 上,你的 html 代码应该是:

$.ajax({
    url: "http://127.0.0.1/a/w/currencies",
    type: "GET",
    dataType: "json",
    data: {
    },
    success: function(data){
        console.log(data);
    }
}); 

on 127.0.0.1, your apache conf should be:在 127.0.0.1 上,你的 apache conf 应该是:

...

<VirtualHost dev:8080>
            ...
            ProxyPass / https://app.somesite.com:5002/
            ProxyPassReverse / https://app.somesitecom:5002/
            ...
</VirtualHost>

on this case, your browser will not cross-domain, because your url and ajax use the same domain.But exactly, ajax request https://app.somesite.com:5002/ , I don't know if it is a reverse-proxy ,but it seems work for me.在这种情况下,你的浏览器不会跨域,因为你的url和ajax使用的是同一个域。但确切地说,ajax请求https://app.somesite.com:5002/ ,不知道是不是反向-proxy ,但它似乎对我有用。 Have a try :)试试 :)

I will be attempting the same thing myself pretty soon which is how I found this thread.我很快就会自己尝试同样的事情,这就是我发现这个线程的方式。

I wonder if the actual url that you are using in the AJAX request is wrong.我想知道您在 AJAX 请求中使用的实际 url 是否错误。 Essentially, you are connecting to the proxy.本质上,您正在连接到代理。 It is forwarding you to the port 8080 address.它会将您转发到端口 8080 地址。 Then you try to make an AJAX request directly to the 8080 address?那你试试直接向8080地址发出AJAX请求? A relative link may work so that the AJAX call gets forwarded along the same path so that javascript knows it's the same origin.相对链接可能会起作用,以便 AJAX 调用沿着相同的路径转发,以便 javascript 知道它的来源相同。

An alternative is backending with PHP.另一种方法是使用 PHP 进行后端。 Lecture 7 of this online course covers AJAX and does an example with PHP to completely circumvent same origin restrictions.本在线课程的第 7 讲涵盖了 AJAX,并使用 PHP 进行了示例以完全规避同源限制。 http://academicearth.org/courses/building-dynamic-websites/ http://academicearth.org/courses/building-dynamic-websites/

I just found this, it seems like a better solution.我刚刚找到了这个,这似乎是一个更好的解决方案。 http://darius.kruythoff.net/blog/2011/xss-with-apache/ http://darius.kruythoff.net/blog/2011/xss-with-apache/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM