php面试题九 -- 常见问题
你用什么方法检查 PHP 脚本的执行效率(通常是脚本执行时间)和数据库 SQL 的效率(通常是数据库 Query 时间), 并定位和分析脚本执行和数据库查询的瓶颈所在?
数据库SQL的效率
sql
的explain(sql)
,启用slow_query_log
记录慢查询。通常还要看数据库设计是否合理,需求是否合理等。
慢查询相关文章MYSQL 慢查询 | 臭大佬
PHP一般是在要检查的代码开头记录一个时间,结尾记录一个时间。取差值。
但这个时间一般来说都很快,在一秒以内,所以不能直接用mktime()
<?php
/**
* 返回当前 Unix 时间戳的微秒数
*/
function microtime_float()
{
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
$time_start = microtime_float();
// 这里放你要检查的代码 --开始
$product = 1;
foreach (range(1, 5) as $val) {
sleep(1);
$product = $product * $val;
}
// 这里放你要检查的代码 -- 结束
$time_end = microtime_float();
$time = $time_end - $time_start;
echo "以上代码块执行时间是: $time 秒\n";
前后端分离情况下,前端在a.com下向b.com请求接口,后端如何解决前端跨域问题
跨域请求
当一台服务器资源从另一台服务器(不同 的域名或者端口)请求一个资源或者接口,就会发起一个跨域 HTTP 请求。举个简单的例子,从http://a.com/index.html
, 发送一个 Ajax
请求,请求地址是 http://b.com/
下面的一个接口,这就是发起了一个跨域请求。在不做任何处理的情况下,这个跨域请求是无法被成功请求的,因为浏览器基于同源策略 会对跨域请求做一定的限制。
同源策略
一个域名请求地址的组成是:协议+域名+端口号+请求资源地址 , 当协议、域名、端口号中任意一个不相同时 , 都算作不同源(必须是域名完全相同,比如说 a.example.com
和 b.example.com
这两个域名。虽然它们的顶级域名和二级域名(均为 example.com
)都相同,但是三级域名(a 和 b)不相同,所以也不能算作域名相同)。如果不同时满足这上面三个条件,那就不符合浏览器的同源策略。
解决方式一:php代码加header头
<?php
header('Access-Control-Allow-Origin:http://www.a.com');
解决方式二:nginx反向代理
通过nginx
配置一个代理服务器(域名与a.com
相同,端口不同)做跳板机,反向代理访问b.com
接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。
// proxy服务器
server {
listen 81;
server_name www.a.com;
location / {
proxy_pass http://www.b.com:8080; #反向代理
proxy_cookie_domain www.b.com www.a.com; #修改cookie里域名
index index.html index.htm;
# 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用
add_header Access-Control-Allow-Origin http://www.a.com; #当前端只跨域不带cookie时,可为*
add_header Access-Control-Allow-Credentials true;
}
}
多个网站域名,(www.a.com,www.b.com,www.c.com),在www.a.com登录,如何保证www.b.com和www.c.com也能同时登录,你的方案是什么
方案一:单点登录
具体流程如下:
用户访问app系统,app系统是需要登录的,但用户现在没有登录。
跳转到CAS server,即SSO登录系统,以后图中的CAS Server我们统一叫做SSO系统。 SSO系统也没有登录,弹出用户登录页。
用户填写用户名、密码,SSO系统进行认证后,将登录状态写入SSO的session,浏览器(Browser)中写入SSO域下的Cookie。
SSO系统登录完成后会生成一个ST(Service Ticket),然后跳转到app系统,同时将ST作为参数传递给app系统。
app系统拿到ST后,从后台向SSO发送请求,验证ST是否有效。
验证通过后,app系统将登录状态写入session并设置app域下的Cookie。
至此,跨域单点登录就完成了。以后我们再访问app系统时,app就是登录的。接下来,我们再看看访问app2系统时的流程。
用户访问app2系统,app2系统没有登录,跳转到SSO。
由于SSO已经登录了,不需要重新登录认证。
SSO生成ST,浏览器跳转到app2系统,并将ST作为参数传递给app2。
app2拿到ST,后台访问SSO,验证ST是否有效。
验证成功后,app2将登录状态写入session,并在app2域下写入Cookie。
方案二:nginx代理
用nginx代理,可以共用同一个cookie从而实现。
不同的端口所保存的cookie是不能通用的,只有通过nginx代理。原理就是当三个服务端口为8080,8081,8082,而配置nginx端口为88;看配置
server {
listen 88;
server_name localhost;
location /server2/{
proxy_pass http://127.0.0.1:8082/server2/;
}
location /server1/ {
proxy_pass http://127.0.0.1:8081/server1/;
}
location /server/ {
proxy_pass http://127.0.0.1:8080/server/;
}
}
需要注意的是localhost后面需要固定服务的地址前缀,这样访问时可以直接访问:http://127.0.0.1:88/servce1/login.html
, 这样就能直接访问到端口为8081的服务。
在附上nginx解决跨域问题的配置
http {
include mime.types;
default_type application/octet-stream;
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers X-Requested-With;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
}
扩展 同域下的单点登录 — 共享session
说到单点登录,还有一种是同域名下的情况,这种情况下,抓住一个点,我们在设置Cookie时,只能设置顶域和自己的域,不能设置其他的域。,可以将Cookie的域设置为顶域,Cookie的问题解决了,
将用户信息,存储在redis中将key作为数据返回页面时,放到cookie中,只要cookie中有key,后续访问逻辑www.xxx.com系统时,都会携带这个key,从而可以处理获取redis的数据使用.